package org.marketcetera.module;
import org.marketcetera.util.misc.ClassVersion;
import java.util.concurrent.locks.Lock;
import java.util.Map;
import java.util.Hashtable;
/* $License$ */
/**
* A module for testing locking within module framework when carrying
* out various module framework operations.
*
* @author anshul@marketcetera.com
* @version $Id: ConcurrentTestModule.java 16154 2012-07-14 16:34:05Z colin $
* @since 1.1.0
*/
@ClassVersion("$Id: ConcurrentTestModule.java 16154 2012-07-14 16:34:05Z colin $")
public class ConcurrentTestModule extends Module
implements DataReceiver, DataEmitter, DataFlowRequester,
ConcurrentTestModuleMXBean {
ConcurrentTestModule(ModuleURN inURN, boolean inAutoStart) {
super(inURN, inAutoStart);
sModules.put(inURN, this);
}
@Override
protected void preStart() throws ModuleException {
//Create a data flow
mFlowID = mSupport.createDataFlow(new DataRequest[]{
new DataRequest(getURN())
});
DataRequest[] requests = getFlowRequests();
if(requests != null) {
mOtherFlowID = mSupport.createDataFlow(requests);
}
//lock after create data flows.
lockIfNotNull(getPreStartLock());
if(isPreStartFail()) {
throw new ModuleException(TestMessages.FAILURE);
}
}
@Override
protected void preStop() throws ModuleException {
lockIfNotNull(getPreStopLock());
if(isPreStopFail()) {
throw new ModuleException(TestMessages.FAILURE);
}
if(mOtherFlowID != null) {
mSupport.cancel(mOtherFlowID);
}
mSupport.cancel(mFlowID);
}
@Override
public void receiveData(DataFlowID inFlowID, Object inData)
throws ReceiveDataException {
//do nothing
}
@Override
public void requestData(DataRequest inRequest, DataEmitterSupport inSupport)
throws RequestDataException {
lockIfNotNull(getRequestDataLock());
}
@Override
public void cancel(DataFlowID inFlowID, RequestID inRequestID) {
lockIfNotNull(getCancelLock());
}
@Override
public void setFlowSupport(DataFlowSupport inSupport) {
mSupport = inSupport;
lockIfNotNull(getSetFlowSupportLock());
}
@Override
public void setValue(String inValue) {
lockIfNotNull(getSetValueLock());
}
/**
* Clears all the testing helper state associated with the module
* instances.
*/
static void clear() {
sHelperTable.clear();
sModules.clear();
}
/**
* Returns the testing helper for the module instance with the
* supplied URN.
*
* @param inURN the URN of the module instance whose helper is needed.
*
* @return the helper for the module instance with the supplied URN.
*/
static Helper helper(ModuleURN inURN) {
Helper helper = sHelperTable.get(inURN);
if (helper == null) {
helper = new Helper();
sHelperTable.put(inURN, helper);
}
return helper;
}
/**
* The module instance, given the module URN.
*
* @param inURN the module instance URN.
*
* @return the module instance having the specified URN, null if a
* module with the supplied URN is not found.
*/
static ConcurrentTestModule getModule(ModuleURN inURN) {
return sModules.get(inURN);
}
/**
* Creates a data flow using the {@link DataFlowSupport} instance supplied
* to the module.
*
* @param inRequests the data requests for setting up the data flow.
*
* @return the ID of the created flow.
*
* @throws ModuleException if there were errors setting up the flow.
*/
DataFlowID createFlow(DataRequest[] inRequests) throws ModuleException {
return mSupport.createDataFlow(inRequests);
}
/**
* The flowID of the flow initiated by this module.
*
* @return the flowID of the flow initiated by this module.
*/
DataFlowID getFlowID() {
return mFlowID;
}
/**
* Cancels the data flow using the {@link DataFlowSupport} instance
* supplied to the module.
*
* @param inFlowID the flowID of the flow that needs to be cancelled.
*
* @throws ModuleException if there were errors setting up the flow.
*/
void cancelFlow(DataFlowID inFlowID) throws ModuleException {
mSupport.cancel(inFlowID);
}
private Lock getSetValueLock() {
Helper helper = getHelper(getURN());
return helper == null? null: helper.mSetValueLock;
}
private Lock getPreStartLock() {
Helper helper = getHelper(getURN());
return helper == null? null: helper.mPreStartLock;
}
private boolean isPreStartFail() {
Helper helper = getHelper(getURN());
return helper == null? false: helper.mPreStartFail;
}
private Lock getPreStopLock() {
Helper helper = getHelper(getURN());
return helper == null? null: helper.mPreStopLock;
}
private boolean isPreStopFail() {
Helper helper = getHelper(getURN());
return helper == null? false: helper.mPreStopFail;
}
private Lock getRequestDataLock() {
Helper helper = getHelper(getURN());
return helper == null? null: helper.mRequestDataLock;
}
private Lock getCancelLock() {
Helper helper = getHelper(getURN());
return helper == null? null: helper.mCancelLock;
}
private Lock getSetFlowSupportLock() {
Helper helper = getHelper(getURN());
return helper == null? null: helper.mSetFlowSupportLock;
}
private DataRequest[] getFlowRequests() {
Helper helper = getHelper(getURN());
return helper == null? null: helper.mFlowRequests;
}
private static void lockIfNotNull(Lock inLock) {
if(inLock != null) {
inLock.lock();
}
}
private static Helper getHelper(ModuleURN inURN) {
return sHelperTable.get(inURN);
}
private static final Map<ModuleURN, Helper> sHelperTable =
new Hashtable<ModuleURN, Helper>();
private static final Map<ModuleURN, ConcurrentTestModule> sModules =
new Hashtable<ModuleURN, ConcurrentTestModule>();
private volatile DataFlowSupport mSupport;
private DataFlowID mFlowID = null;
private DataFlowID mOtherFlowID = null;
/**
* Helper class for testing.
*/
static class Helper {
/**
* Sets the lock that should be acquired from within
* {@link ConcurrentTestModule#setValue(String)}.
*
* @param inSetValueLock the lock instance.
*
* @return the helper instance.
*/
public Helper setSetValueLock(Lock inSetValueLock) {
mSetValueLock = inSetValueLock;
return this;
}
/**
* Sets the lock that should be acquired from within
* {@link ConcurrentTestModule#preStart()}.
*
* @param inPreStartLock the lock instance.
*
* @return the helper instance.
*/
public Helper setPreStartLock(Lock inPreStartLock) {
mPreStartLock = inPreStartLock;
return this;
}
/**
* Sets if preStart() should fail.
*
* @param inPreStartFail if preStart() should fail
*
* @return the helper instance.
*/
public Helper setPreStartFail(boolean inPreStartFail) {
mPreStartFail = inPreStartFail;
return this;
}
/**
* Sets the lock that should be acquired from within
* {@link ConcurrentTestModule#preStop()}.
*
* @param inPreStopLock the lock instance.
*
* @return the helper instance.
*/
public Helper setPreStopLock(Lock inPreStopLock) {
mPreStopLock = inPreStopLock;
return this;
}
/**
* Sets if preStop() should fail.
*
* @param inPreStopFail if preStop() should fail.
*
* @return the helper instance.
*/
public Helper setPreStopFail(boolean inPreStopFail) {
mPreStopFail = inPreStopFail;
return this;
}
/**
*
* @param inRequestDataLock the lock instance.
*
* @return the helper instance.
*/
public Helper setRequestDataLock(Lock inRequestDataLock) {
mRequestDataLock = inRequestDataLock;
return this;
}
/**
* Sets the lock that should be acquired from within
* {@link ConcurrentTestModule#cancel(DataFlowID, RequestID)}.
*
* @param inCancelLock the lock instance.
*
* @return the helper instance.
*/
public Helper setCancelLock(Lock inCancelLock) {
mCancelLock = inCancelLock;
return this;
}
/**
* Sets the lock that should be acquired from within
* {@link ConcurrentTestModule#setFlowSupport(DataFlowSupport)}.
*
* @param inSetFlowSupportLock the lock instance.
*
* @return the helper instance.
*/
public Helper setSetFlowSupportLock(Lock inSetFlowSupportLock) {
mSetFlowSupportLock = inSetFlowSupportLock;
return this;
}
/**
* Sets flow requests that should be used to set up data flow
* from within preStart().
*
* @param inFlowRequests flow requests.
*
* @return the helper instance.
*/
public Helper setFlowRequests(DataRequest[] inFlowRequests) {
mFlowRequests = inFlowRequests;
return this;
}
private volatile Lock mSetValueLock = null;
private volatile Lock mPreStartLock = null;
private volatile boolean mPreStartFail = false;
private volatile Lock mPreStopLock = null;
private volatile boolean mPreStopFail = false;
private volatile Lock mRequestDataLock = null;
private volatile Lock mCancelLock = null;
private volatile Lock mSetFlowSupportLock = null;
private volatile DataRequest[] mFlowRequests = null;
}
}