/*
Copyright (c) 2003-2009 ITerative Consulting Pty Ltd. All Rights Reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
o Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
o Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the distribution.
o This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
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