package Express.services;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Hashtable;
import org.apache.log4j.Logger;
import Framework.Constants;
import Framework.ErrorMgr;
import Framework.EventManager;
import Framework.ImplementationException;
import Framework.IntegerData;
import Framework.RemoteEvent;
import Framework.RemoteEventProxy;
import Framework.RuntimeProperties;
import Framework.ServiceObjectContext;
import Framework.TextData;
import Framework.anchored.Anchorable;
import Framework.anchored.AnchoredProxy;
import Framework.anchored.ServiceInvoker;
import Framework.remoting.parameters.CopyInput;
import Framework.remoting.parameters.Input;
/**
* The ConcurrencyMgr class is an internal class and none of its members are documented, except for some of its constants, which are used by two BusinessClient methods: Select and Update.
* <p>
* @author ITerative Consulting
* @since 26-Feb-2008
*/
@SuppressWarnings("deprecation")
@RuntimeProperties(isDistributed=true, isAnchored=true, isShared=true, isTransactional=false)
public class ConcurrencyMgr
implements Serializable, Anchorable
{
// ---------
// Constants
// ---------
public static final int CA_NONE = 0;
public static final int CA_WRITETHRU = 1;
public static final int CO_DB_EXPLICIT = 3;
public static final int CO_DB_NATIVE = 1;
public static final int CO_MASK_CUSTOM = 8;
public static final int CO_MASK_DB = 1;
public static final int CO_MASK_LOCK = 2;
public static final int CO_MASK_OPTIMISTIC = 4;
public static final int CO_NONE = 0;
public static final int CO_OPT_EXPRESS = 20;
public static final int CO_OPT_VERIFY = 4;
public static final int TR_CONTINUE = 0;
public static final int TR_END = 2;
public static final int TR_SINGLETON = 3;
public static final int TR_START = 1;
public static final int TRACE_COMMIT = 30;
public static final int TRACE_ID = 1;
public static final int TRACE_LOAD = 50;
public static final int TRACE_READY = 40;
public static final int TRACE_ROLLBACK = 20;
public static final int TRACE_START = 60;
public static final int TS_ACTIVE = 1;
public static final int TS_INACTIVE = 0;
// ----------
// Attributes
// ----------
private int cacheMode;
private int cacheSize;
private int concurrencyMode;
private int freeUserCBhead;
private ConcurrencyKeys keys;
private int oldestTimeIndex;
private int timeIndex;
private Trace trace;
private int updateDelay;
private Array_Of_ConcurrencyUserCB<ConcurrencyUserCB> users;
/**
* The flag to use for "isAnchored" and the listener for remote requests
*/
protected ServiceInvoker invoker = null;
// ------------
// Constructors
// ------------
public ConcurrencyMgr() {
this(true);
this.setTrace(new Trace());
this.getTrace().setDefaultServiceID(Constants.SP_ST_EX);
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_INIT, 1, this, "Init")) {
Logger.getLogger("task.part.logmgr").info("Address = ");
Logger.getLogger("task.part.logmgr").info(this);
}
}
public ConcurrencyMgr(ServiceObjectContext pContext) {
}
public ConcurrencyMgr(boolean pIsAnchored) {
this.setIsAnchored(pIsAnchored);
}
// ----------------------
// Accessors and Mutators
// ----------------------
public synchronized int getCacheMode() {
return this.cacheMode;
}
public synchronized int getConcurrencyMode() {
return this.concurrencyMode;
}
public synchronized void setFreeUserCBhead(int freeUserCBhead) {
this.freeUserCBhead = freeUserCBhead;
}
public synchronized int getFreeUserCBhead() {
return this.freeUserCBhead;
}
public synchronized void setTrace(Trace trace) {
this.trace = trace;
}
public synchronized Trace getTrace() {
return this.trace;
}
public boolean getIsAnchored() {
return invoker != null;
}
public void setIsAnchored(boolean isAnchored) {
if (isAnchored && invoker == null) {
// Anchor the object, creating an invoker for it.
this.invoker = new ServiceInvoker(this);
}
else if (!isAnchored && invoker != null) {
this.invoker = null;
}
}
/**
* Get the invoker for this class. This method should only be called from the proxy, hence the protected level visibility.
*/
protected ServiceInvoker getInvoker(ConcurrencyMgr pService) {
return pService.invoker;
}
// -------
// Methods
// -------
/**
* commitTrans<p>
* <p>
* @param clientID Type: int
* @param transactionMode Type: int
*/
public synchronized void commitTrans(@CopyInput int clientID, @CopyInput int transactionMode) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_CM, ConcurrencyMgr.TRACE_COMMIT, this, "CommitTrans")) {
Logger.getLogger("task.part.logmgr").info("clientID = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(clientID));
Logger.getLogger("task.part.logmgr").info(", transactionMode = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(transactionMode));
}
ConcurrencyUserCB userCB = this.getUserCB(clientID);
if (userCB.getStamp() == 0) {
throw new Error(Error.CM_NO_TRANSACTION, "CommitTrans", this, new IntegerData(clientID), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
else {
userCB.setStamp(this.getTimestamp());
Array_Of_ConcurrencyKeyCB<ConcurrencyKeyCB> qq_localVector = userCB.getLockedKeys();
if (qq_localVector != null) {
for (ConcurrencyKeyCB keyCB : qq_localVector) {
keyCB.setLocked(false);
keyCB.setStamp(userCB.getStamp());
keyCB.setUpdateStamp(userCB.getStamp());
}
}
userCB.setLockedKeys(null);
if ((transactionMode&ConcurrencyMgr.TR_END) > 0) {
this.endTrans(userCB);
}
}
}
/**
* endTrans<p>
* <p>
* @param userCB Type: ConcurrencyUserCB
*/
private synchronized void endTrans(@Input ConcurrencyUserCB userCB) {
Array_Of_ConcurrencyKeyCB<ConcurrencyKeyCB> qq_localVector = userCB.getKeys();
if (qq_localVector != null) {
for (ConcurrencyKeyCB keyCB : qq_localVector) {
this.keys.drop(keyCB, this.oldestTimeIndex);
}
}
//
// We need to keep certain information for all transactions currently active.
// This is identified by the attribute OldestTimeIndex. Everything since
// then needs to be saved. If we are ending the transaction that started
// at OldestTimeIndex it (OldestTimeIndex) is now older than it needs to
// be. The problem is figuring out the new OldestTimeIndex. It requires
// looking at every transaction. We don't want to do that too often, and
// it doesn't hurt to have OldestTimeIndex a little older than it needs to
// be, we will just use a little more memory saving things we don't need to.
// So we delay Updating the OldestTimeIndex until we've committed as many
// transactions as we have room in the cache. Then we scan the Users table
// and look for the oldest transaction currently active.
//
if (userCB.getStamp() == this.oldestTimeIndex || this.updateDelay > 0) {
this.updateDelay = this.updateDelay+1;
if (this.updateDelay > this.cacheSize) {
this.updateDelay = 0;
userCB.setStamp(0);
this.oldestTimeIndex = 2147483647;
// 2**31-1
if (this.users != null) {
for (ConcurrencyUserCB u : this.users) {
if ((u.getStamp() > 0) && (u.getStamp() < this.oldestTimeIndex)) {
this.oldestTimeIndex = u.getStamp();
}
}
}
if (this.oldestTimeIndex == 2147483647) {
//
// Since we seem to have no active transactions right now we'll
// have set update delay now to start the counter going until
// we check again.
//
this.updateDelay = 1;
}
}
}
userCB.setStamp(0);
userCB.setKeys(null);
}
/**
* fetch<p>
* <p>
* @param key Type: BusinessKey
* @return BusinessClass
*/
public synchronized BusinessClass fetch(@Input BusinessKey key) {
ImplementationException e = new ImplementationException();
e.setWithParams(Constants.SP_ER_ERROR, new TextData("The method Cache.Fetch is unimplemented."));
ErrorMgr.addError(e);
throw e;
}
// Method GetCacheMode() : integer skipped because it is replaced by accessor / mutator.
/**
* getClientID<p>
* <p>
* @return int
*/
public synchronized int getClientID() {
if (this.users == null) {
this.setup();
}
ConcurrencyUserCB userCB = null;
int id = this.getFreeUserCBhead();
if (id == ConcurrencyUserCB.END_OF_LIST) {
userCB = new ConcurrencyUserCB();
userCB.setNext(ConcurrencyUserCB.IN_USE);
this.users.add(userCB);
id = this.users.size();
}
else {
userCB = this.users.get(this.getFreeUserCBhead()-1);
this.setFreeUserCBhead(userCB.getNext());
userCB.initialise();
userCB.setNext(ConcurrencyUserCB.IN_USE);
}
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_CM, ConcurrencyMgr.TRACE_ID, this, "GetClientID")) {
Logger.getLogger("task.part.logmgr").info("clientID = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(id));
}
return id;
}
// Method GetConcurrencyMode() : integer skipped because it is replaced by accessor / mutator.
/**
* getTimestamp<p>
* <p>
* @return int
*/
private synchronized int getTimestamp() {
this.timeIndex = this.timeIndex+1;
return this.timeIndex;
}
/**
* getUserCB<p>
* <p>
* @param clientID Type: int
* @return ConcurrencyUserCB
*/
private synchronized ConcurrencyUserCB getUserCB(@Input int clientID) {
if (clientID <= 0 || clientID > this.users.size()) {
throw new Error(Error.CM_ILLEGAL_CLIENT_ID, "GetUserCB", this, new IntegerData(clientID), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
else {
ConcurrencyUserCB userCB = this.users.get(clientID-1);
if (userCB.getNext() != ConcurrencyUserCB.IN_USE) {
throw new Error(Error.CM_ILLEGAL_CLIENT_ID, "GetUserCB", this, new IntegerData(clientID), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
return userCB;
}
}
/**
* load<p>
* <p>
* @param clientID Type: int
* @param transactionMode Type: int
* @param source Type: Array_Of_BusinessKey<BusinessKey>
*/
public synchronized void load(@CopyInput int clientID, @CopyInput int transactionMode, @CopyInput Array_Of_BusinessKey<BusinessKey> source) {
ConcurrencyUserCB userCB = this.getUserCB(clientID);
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_CM, ConcurrencyMgr.TRACE_LOAD, this, "Load")) {
Logger.getLogger("task.part.logmgr").info("clientID = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(clientID));
Logger.getLogger("task.part.logmgr").info(", transactionMode = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(transactionMode));
Logger.getLogger("task.part.logmgr").info(", keys = ");
if (source != null) {
for (BusinessKey i : source) {
Logger.getLogger("task.part.logmgr").info(i.asTextData());
Logger.getLogger("task.part.logmgr").info(", ");
}
}
Logger.getLogger("task.part.logmgr").info("");
}
if (userCB.getStamp() == 0) {
throw new Error(Error.CM_NO_TRANSACTION, "Load", this, new IntegerData(clientID), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
else {
ConcurrencyKeyCB keyCB = null;
if (source != null) {
for (BusinessKey i : source) {
keyCB = this.keys.get(i);
if (keyCB == null) {
keyCB = new ConcurrencyKeyCB();
keyCB.setKey(i);
keyCB.setStamp(userCB.getStamp());
this.keys.add(keyCB);
}
else if (keyCB.getStamp() > userCB.getStamp() && keyCB.getUpdateStamp() == 0 && !(keyCB.getLocked())) {
//
// This is one case in which we can safely back up the timestamp
// associated with the record. If we don't do this then we won't
// be able to update it eventhough it is the same in the DB as
// what we selected. The fact the someone with a later starting
// transacton timestamp selected it first would spoof us.
// NOTE: doing this requires that we not remove keyCBs that have
// been updated until all transactions started before the update
// have completed.
//
keyCB.setStamp(userCB.getStamp());
}
userCB.getKeys().add(keyCB);
keyCB.setCount(keyCB.getCount()+1);
}
}
}
}
/**
* load<p>
* <p>
* @param clientID Type: int
* @param transactionMode Type: int
* @param source Type: Array_Of_BusinessClass<BusinessClass>
*/
public synchronized void load(@CopyInput int clientID, @CopyInput int transactionMode, @CopyInput Array_Of_BusinessClass<BusinessClass> source) {
ConcurrencyUserCB userCB = this.getUserCB(clientID);
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_CM, ConcurrencyMgr.TRACE_LOAD, this, "Load")) {
Logger.getLogger("task.part.logmgr").info("clientID = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(clientID));
Logger.getLogger("task.part.logmgr").info(", transactionMode = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(transactionMode));
Logger.getLogger("task.part.logmgr").info(", keys = ");
if (source != null) {
for (BusinessClass i : source) {
Logger.getLogger("task.part.logmgr").info(i.getInstanceKey().asTextData());
Logger.getLogger("task.part.logmgr").info(", ");
}
}
Logger.getLogger("task.part.logmgr").info("");
}
if (userCB.getStamp() == 0) {
throw new Error(Error.CM_NO_TRANSACTION, "Load", this, new IntegerData(clientID), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
else {
ConcurrencyKeyCB keyCB = null;
if (source != null) {
for (BusinessClass i : source) {
keyCB = this.keys.get(i.getInstanceKey());
if (keyCB == null) {
keyCB = new ConcurrencyKeyCB();
keyCB.setKey(i.getInstanceKey());
keyCB.setObj(i);
keyCB.setStamp(userCB.getStamp());
this.keys.add(keyCB);
}
else if (keyCB.getStamp() > userCB.getStamp() && keyCB.getUpdateStamp() == 0 && !(keyCB.getLocked())) {
//
// This is one case in which we can safely back up the timestamp
// associated with the record. If we don't do this then we won't
// be able to update it eventhough it is the same in the DB as
// what we selected. The fact the someone with a later starting
// transacton timestamp selected it first would spoof us.
// NOTE: doing this requires that we not remove keyCBs that have
// been updated until all transactions started before the update
// have completed.
//
keyCB.setStamp(userCB.getStamp());
}
userCB.getKeys().add(keyCB);
keyCB.setCount(keyCB.getCount()+1);
}
}
}
}
/**
* readyToCommit<p>
* <p>
* @param clientID Type: int
* @param transactionMode Type: int
* @param source Type: Array_Of_BusinessKey<BusinessKey>
*/
public synchronized void readyToCommit(@CopyInput int clientID, @CopyInput int transactionMode, @CopyInput Array_Of_BusinessKey<BusinessKey> source) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_CM, ConcurrencyMgr.TRACE_READY, this, "ReadyToCommit")) {
Logger.getLogger("task.part.logmgr").info("clientID = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(clientID));
Logger.getLogger("task.part.logmgr").info(", transactionMode = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(transactionMode));
}
ConcurrencyUserCB userCB = this.getUserCB(clientID);
if (userCB.getStamp() == 0) {
userCB.setStamp(this.getTimestamp());
userCB.setKeys(new Array_Of_ConcurrencyKeyCB<ConcurrencyKeyCB>());
if (source.size() <= 0) {
return;
// efficiency for updates that are just inserts.
}
else {
// This allows Updates that are singletons.
//raise Error(Originator=self, MethodName='ReadyToCommit', Error=Error.CM_NO_TRANSACTION, Param1=IntegerData(value=clientID)).GetException;
}
}
ConcurrencyKeyCB keyCB = null;
userCB.setLockedKeys(new Array_Of_ConcurrencyKeyCB<ConcurrencyKeyCB>());
if (source != null) {
for (BusinessKey key : source) {
keyCB = this.keys.get(key);
if (keyCB == null) {
keyCB = new ConcurrencyKeyCB();
keyCB.setKey(key);
keyCB.setStamp(userCB.getStamp());
this.keys.add(keyCB);
}
if (keyCB.getLocked() || keyCB.getStamp() > userCB.getStamp()) {
Array_Of_ConcurrencyKeyCB<ConcurrencyKeyCB> qq_localVector = userCB.getLockedKeys();
if (qq_localVector != null) {
for (ConcurrencyKeyCB k : qq_localVector) {
k.setLocked(false);
}
}
userCB.setLockedKeys(null);
this.endTrans(userCB);
throw new Error(Error.CM_CLASS_CHANGED, "ReadyToCommit", this, key, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
userCB.getLockedKeys().add(keyCB);
keyCB.setLocked(true);
}
}
userCB.setStamp(this.getTimestamp());
}
/**
* relClientID<p>
* <p>
* @param clientID Type: int
*/
public synchronized void relClientID(@CopyInput int clientID) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_CM, ConcurrencyMgr.TRACE_ID, this, "RelClientID")) {
Logger.getLogger("task.part.logmgr").info("clientID = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(clientID));
}
ConcurrencyUserCB userCB = this.getUserCB(clientID);
this.endTrans(userCB);
userCB.setNext(this.getFreeUserCBhead());
this.setFreeUserCBhead(clientID);
}
/**
* rollback<p>
* <p>
* @param clientID Type: int
* @param transactionMode Type: int (Copy Input) (default in Forte: 0)
*/
public synchronized void rollback(@CopyInput int clientID, @CopyInput int transactionMode) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_CM, ConcurrencyMgr.TRACE_ROLLBACK, this, "Rollback")) {
Logger.getLogger("task.part.logmgr").info("clientID = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(clientID));
Logger.getLogger("task.part.logmgr").info(", transactionMode = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(transactionMode));
}
ConcurrencyUserCB userCB = this.getUserCB(clientID);
if (userCB.getStamp() == 0) {
throw new Error(Error.CM_NO_TRANSACTION, "Rollback", this, new IntegerData(clientID), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
else {
Array_Of_ConcurrencyKeyCB<ConcurrencyKeyCB> qq_localVector = userCB.getLockedKeys();
if (qq_localVector != null) {
for (ConcurrencyKeyCB keyCB : qq_localVector) {
keyCB.setLocked(false);
}
}
userCB.setLockedKeys(null);
if ((transactionMode&ConcurrencyMgr.TR_END) > 0) {
this.endTrans(userCB);
}
}
}
/**
* qq_setCacheMode<p>
* Method renamed by jcTOOL from SetCacheMode to qq_setCacheMode
* because it conflicted with an attribute<p>
* <p>
* @param mode Type: int
*/
public synchronized void qq_setCacheMode(@Input int mode) {
switch (mode) {
case ConcurrencyMgr.CA_NONE: {
this.cacheMode = ConcurrencyMgr.CA_NONE;
break;
}
case ConcurrencyMgr.CA_WRITETHRU: {
this.cacheMode = ConcurrencyMgr.CA_WRITETHRU;
break;
}
default: {
throw new Error(Error.CM_ILLEGAL_CACHE_MODE, "SetCacheMode", this, new IntegerData(mode), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
}
}
/**
* qq_setCacheSize<p>
* Method renamed by jcTOOL from SetCacheSize to qq_setCacheSize
* because it conflicted with an attribute<p>
* <p>
* @param size Type: int
*/
public synchronized void qq_setCacheSize(@Input int size) {
ImplementationException e = new ImplementationException();
e.setWithParams(Constants.SP_ER_ERROR, new TextData("The method CacheMgr.SetCacheSize is umimplemented."));
ErrorMgr.addError(e);
throw e;
}
/**
* qq_setConcurrencyMode<p>
* Method renamed by jcTOOL from SetConcurrencyMode to qq_setConcurrencyMode
* because it conflicted with an attribute<p>
* <p>
* @param mode Type: int
*/
public synchronized void qq_setConcurrencyMode(@Input int mode) {
if (this.concurrencyMode != mode) {
if (this.concurrencyMode != ConcurrencyMgr.CO_NONE) {
throw new Error(Error.CM_CANNOT_CHANGE_MODE, "SetConcurrencyMode", this, new IntegerData(this.concurrencyMode), new IntegerData(mode)).getException();
}
switch (mode) {
case ConcurrencyMgr.CO_NONE: {
this.concurrencyMode = ConcurrencyMgr.CO_NONE;
break;
}
case ConcurrencyMgr.CO_DB_NATIVE: {
this.concurrencyMode = ConcurrencyMgr.CO_DB_NATIVE;
break;
}
case ConcurrencyMgr.CO_DB_EXPLICIT: {
this.concurrencyMode = ConcurrencyMgr.CO_DB_EXPLICIT;
break;
}
case ConcurrencyMgr.CO_OPT_VERIFY: {
this.concurrencyMode = ConcurrencyMgr.CO_OPT_VERIFY;
break;
}
case ConcurrencyMgr.CO_OPT_EXPRESS: {
this.concurrencyMode = ConcurrencyMgr.CO_OPT_EXPRESS;
break;
}
default: {
throw new Error(Error.CM_ILLEGAL_CONCURRENCY_MODE, "SetConcurrencyMode", this, new IntegerData(mode), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
}
}
}
/**
* setup<p>
* <p>
*/
public synchronized void setup() {
if (this.cacheSize == 0) {
this.cacheSize = 1000;
}
this.users = new Array_Of_ConcurrencyUserCB<ConcurrencyUserCB>();
this.keys = new ConcurrencyKeys();
this.keys.setup(this.cacheSize);
this.setFreeUserCBhead(ConcurrencyUserCB.END_OF_LIST);
this.updateDelay = 1;
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_INIT, 1, this, "Setup")) {
Logger.getLogger("task.part.logmgr").info("Address = ");
Logger.getLogger("task.part.logmgr").info( Integer.toHexString(this.hashCode()));
Logger.getLogger("task.part.logmgr").info(", Size = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(this.cacheSize));
}
}
/**
* startTrans<p>
* <p>
* @param clientID Type: int
* @param transactionMode Type: int
*/
public synchronized void startTrans(@CopyInput int clientID, @CopyInput int transactionMode) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_CM, ConcurrencyMgr.TRACE_START, this, "StartTrans")) {
Logger.getLogger("task.part.logmgr").info("clientID = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(clientID));
Logger.getLogger("task.part.logmgr").info(", transactionMode = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(transactionMode));
}
ConcurrencyUserCB userCB = this.getUserCB(clientID);
if (transactionMode == ConcurrencyMgr.TR_CONTINUE) {
if (userCB.getStamp() == 0) {
throw new Error(Error.CM_NO_TRANSACTION, "StartTrans", this, new IntegerData(clientID), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
}
else {
if (userCB.getStamp() > 0) {
if (userCB.getLockedKeys() == null) {
this.endTrans(userCB);
}
else {
Array_Of_ConcurrencyKeyCB<ConcurrencyKeyCB> qq_localVector = userCB.getLockedKeys();
if (qq_localVector != null) {
for (ConcurrencyKeyCB keyCB : qq_localVector) {
keyCB.setLocked(false);
keyCB.setStamp(userCB.getStamp());
keyCB.setUpdateStamp(userCB.getStamp());
}
}
userCB.setLockedKeys(null);
this.endTrans(userCB);
throw new Error(Error.CM_TRANSACTION_IN_PROGRESS, "StartTrans", this, new IntegerData(clientID), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
}
if (transactionMode == ConcurrencyMgr.TR_START) {
userCB.setStamp(this.getTimestamp());
userCB.setKeys(new Array_Of_ConcurrencyKeyCB<ConcurrencyKeyCB>());
}
}
}
/**
* Get the proxy class which will forwards remote requests to this class. This
* must be kept as a method so it can be overridden in all subclasses, ensuring
* a proxy to the lowest level subclass is returned.
*/
public AnchoredProxy getProxy() {
return new ConcurrencyMgrProxy(this);
}
/**
* Override the writeReplace method to replace this class with a proxy to it (if it's anchored)
*/
public Object writeReplace() throws ObjectStreamException {
if (getIsAnchored()) {
AnchoredProxy proxy = this.getProxy();
//System.out.println("Replacing " + this + " with " + proxy + " in writeReplace");
return proxy;
}
else {
return this;
}
}
/**
* Satisfy the {@link RemoteEventProxy} interface
*/
public String registerInterest(String pHostName, RemoteEvent pAnchoredObject, String pEvent) {
return EventManager.registerInterest(pHostName, pAnchoredObject, this, pEvent);
}
public void postEvent(String pEventName, Hashtable<String, Object> pParameters) {
EventManager.postEvent(this, pEventName, pParameters);
}
public void deregisterInterest(String pHostName, RemoteEvent pAnchoredObject, String pEvent) {
EventManager.deregisterInterest(pHostName, pAnchoredObject, this, pEvent);
}
} // end class ConcurrencyMgr
// c Pass 2 Conversion Time: 3282 milliseconds