/*
* ACEVoidTransactionActionImpl
*
* 07/17/2003
*
* Copyright:
* Licensed Materials - Property of IBM
* "Restricted Materials of IBM"
* 5724-AEF
* (C) Copyright IBM Corp. 2003.
*
* %W% %E%
*/
package com.ibm.retail.AEF.action;
import com.ibm.retail.AEF.automation.*;
import com.ibm.retail.AEF.util.*;
import com.ibm.retail.si.util.*;
import com.ibm.retail.si.Copyright;
import com.ibm.retail.AEF.factory.*;
import com.ibm.retail.AEF.thread.*;
import com.ibm.retail.AEF.data.*;
import com.ibm.retail.AEF.session.*;
import java.util.*;
import java.rmi.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* ACEVoidTransactionActionImpl is a class which the POSAutomationProvider uses to
* void the current transaction.
*
*/
public class ACEVoidTransactionActionImpl extends ACEActionImpl
{
static String copyright()
{ return com.ibm.retail.si.Copyright.IBM_COPYRIGHT_SHORT; }
private static AEFPerfTrace perfTrace = AEFPerfTrace.getInstance();
/**
* Constructor
*
* @param request The ActionRequest which contains a HashMap of arguments.
* @exception AEFException
* AEFException error codes:
*
AEFConst.CONFIG_ERROR, AEFConst.FACTORY_ERROR
*/
public ACEVoidTransactionActionImpl(ActionRequest request) throws AEFException
{
super(request);
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter/-Exit constructor of ACEVoidTransactionActionImpl.");
log.trace(tempAEFMessage);
}
}
/**
* Tries to void the current transaction and return the application to the MAIN state
* and SELECT_PROCEDURE substate as defined in the configuration files.
*
* @param request The ActionRequest which contains the classname and arguments.
* @return Object N/A (null).
* @exception AEFException
* AEFException Error Codes:
*
AEFConst.PROCEDURE_NOT_ALLOWED, AEFConst.TRANSACTION_NOT_ACTIVE
*
AEFConst.APPLICATION_NOT_IN_PROPER_STATE
*/
public Object performAction() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter ACEVoidTransactionActionImpl.performAction()");
log.trace(tempAEFMessage);
}
// Call super to perform any common processing and clear any errors before we start.
super.performAction();
// If app is in secured state, and options are set to automatically do a special
// signon, then do a special signon first.
checkForSpecialSignon();
boolean salesTranInProgress = false;
boolean nonSalesTranInProgress = false;
Transaction trans = null;
ObjectDetector detector = null;
try
{
// Check that we are in the middle of a transaction.
salesTranInProgress = getBooleanProviderProperty(WorkstationStatusProperties.CATEGORY,
WorkstationStatusProperties.SALES_TRANSACTION_IN_PROGRESS);
nonSalesTranInProgress = getBooleanProviderProperty(WorkstationStatusProperties.CATEGORY,
WorkstationStatusProperties.NONSALES_TRANSACTION_IN_PROGRESS);
trans = automationProvider.getTransaction();
if (!salesTranInProgress && !nonSalesTranInProgress && trans == null)
{
// Not in the middle of the transaction.
String tempString = "ACEVoidTransactionActionImpl.performAction(): Cannot void a transaction because no transaction is in progress.";
AEFException tempException = new AEFException(AEFConst.PROCEDURE_NOT_ALLOWED,
AEFConst.TRANSACTION_NOT_ACTIVE,
tempString);
tempAEFMessage.setMessage(tempString);
log.error(tempAEFMessage, tempException);
throw tempException;
}
// Check for a "partial" transaction which was started, but no items have been sold.
if (trans != null)
{
if (trans.getTransactionInfo().getTransactionID() == null)
{
// Clear the partial transaction object.
if (log.isDebugEnabled())
{
log.debug("ACEVoidTransactionActionImpl clear partial transaction.");
}
thePartialTransactionFlag = true;
trans.setIsActive(false);
detector = ((DetectorAccess)(SessionContext.getSession())).getTransactionDetector();
detector.reset();
automationProvider.setTransaction(null);
}
}
// Get all the states and substates from the config files.
initializeStates();
initializeSubStates();
// theValidSubstates contains a list of all the substates for which
// a transaction can be voided. This is a class static, so it is only
// initialized once.
if (theValidSubstates == null)
{
theValidSubstates = new Vector();
theValidSubstates.addElement(Substate.getSubstate("EXPECTING_ITEM"));
theValidSubstates.addElement(Substate.getSubstate("EXPECTING_TENDER"));
theValidSubstates.addElement(Substate.getSubstate("EXPECTING_COUPON"));
theValidSubstates.addElement(Substate.getSubstate("ENTER_ITEM"));
}
String currentSubstate = getCurrentSubstate();
// If we are not in a substate where we can void the transaction, we will
// attempt a CLEAR first
for (int i = 0; i < 4 && !theValidSubstates.contains(currentSubstate); i++)
{
sendClearSequence(true, false);
currentSubstate = getCurrentSubstate();
}
// VOID TOTAL can be sent if -
// a transaction has items and is in substate 1001 (EXPECTING_ITEM=1001)
// a transaction has items and is in substate 1005 (EXPECTING_COUPON=1005)
// a transaction has items, has been totalled and is in substate 1002 (EXPECTING_TENDER=1002)
if (theValidSubstates.contains(currentSubstate))
{
try
{
sendVoidSequence();
}
catch (AEFException e)
{
// Check to see if we timed out. If so log the error but continue,
// we may be in a state which we can fix below.
if (e.getErrorCode() != AEFConst.OPERATION_TIMEOUT)
{
throw(e);
}
else
{
if (log.isDebugEnabled())
{
log.debug("ACEVoidTransactionActionImp.performAction timeout after sendVoidSequence().");
}
}
}
}
// Get the current sub-state and see if we are in mainstate and mainsubstate
// or in ID state.
if (((!(getCurrentState().equalsIgnoreCase(theMainState))) ||
(!(getCurrentSubstate().equalsIgnoreCase(theMainSubState)))) &&
(!(getCurrentState().equalsIgnoreCase(theIdState))))
{
String tempString = "ACEVoidTransactionActionImpl.performAction(): The application is in state " + getCurrentState() + " substate " + getCurrentSubstate() + " but should be in state " + theMainState + " substate " + theMainSubState + " or in state " + theIdState + ".";
AEFException tempException = new AEFException(AEFConst.APPLICATION_NOT_IN_PROPER_STATE,
0,
tempString);
tempAEFMessage.setMessage(tempString);
log.error(tempAEFMessage, tempException);
throw tempException;
}
}
catch (RemoteException re)
{
// Not expected to get here since we are calling locally.
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit ACEVoidTransactionActionImpl.performAction()");
log.trace(tempAEFMessage);
}
return null;
}
/**
* Sends the key sequence required to void a transaction when not in ITEMENTRY state.
*
* @param wait True to wait for a state transition to state ITEMENTRY.
* @return int Integer value representing the result of the key sequence.
* @exception AEFException
* AEFException error codes:
*
AEFConst.CONFIG_ERROR, AEFConst.FACTORY_ERROR
*/
public int sendVoidSequence(boolean wait) throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter ACEVoidTransactionActionImpl.sendVoidSequence()");
log.trace(tempAEFMessage);
}
int retVal = -1;
AEFErrorHandler errorHandler = null;
args.clear();
args.put("SEQUENCE_ID", "voidTransaction");
theKeySequenceAction = (AEFAction)
(actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction",
args)));
if (wait)
{
// Good state is state 10 and ss 11038
Condition andConds1[] =
{
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY,
POSDeviceProperties.POS_STATE,
State.getState("MAIN")),
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY,
POSDeviceProperties.POS_SUB_STATE,
Substate.getSubstate("SELECT_PROCEDURE"))
};
Condition conditions[] =
{
new AndCondition(andConds1)
};
Condition conditionsP[] = null;
Condition goodConditions[] = null;
if (thePartialTransactionFlag)
{
conditionsP = new Condition[1];
Condition newCond = new PropertyEqualsCondition(POSDeviceProperties.CATEGORY,
POSDeviceProperties.POS_SUB_STATE,
Substate.getSubstate("INVALID_KEY_SEQUENCE"));
conditionsP[0] = newCond;
}
if(conditionsP != null)
{
goodConditions = new Condition[conditions.length + conditionsP.length];
int i = 0;
for (; i < conditions.length; i++)
{
goodConditions[i] = conditions[i];
}
goodConditions[i] = conditionsP[0];
}
else
{
goodConditions = new Condition[conditions.length];
int i=0;
for(; i< conditions.length; i++)
{
goodConditions[i] = conditions[i];
}
}
theLock = new ConditionLock();
if (perfTrace.isEnabled(AEFPerfTrace. COARSE))
{
perfTrace.reportTimer(AEFPerfTrace. COARSE,
sessionID,
"voidTransaction",
">>>Sending void transaction key sequence to application.");
}
retVal = theLock.performActionAndWait("wait-for-state-main",
theKeySequenceAction,
goodConditions,
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout());
if (log.isDebugEnabled())
{
log.debug( new AEFMessage( sessionID, "ACEVoidTransactionActionImp.sendVoidSequence: " +
"Return Value = " + retVal + " State = " + getCurrentState() +
" Substate = " + getCurrentSubstate() + "."));
}
if (retVal < 0)
{
errorHandler = new AEFErrorHandler("Send Void Sequence Error");
retVal = errorHandler.handleError(theLock,
theKeySequenceAction,
conditions,
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout(),
retVal);
if (retVal < 0)
{
throw errorHandler.getAllExceptions();
}
}
else
{
String currentSubstate = getCurrentSubstate();
if (currentSubstate == Substate.getSubstate("INVALID_KEY_SEQUENCE") )
{
// send a clear
sendClearSequence(true, false);
}
}
}
else
{
if (perfTrace.isEnabled(AEFPerfTrace. COARSE))
{
perfTrace.reportTimer(AEFPerfTrace. COARSE,
sessionID,
"voidTransaction",
">>>Sending void transaction key sequence to application.");
}
theKeySequenceAction.performAction();
}
if (perfTrace.isEnabled(AEFPerfTrace. COARSE))
{
perfTrace.reportTimer(AEFPerfTrace. COARSE,
sessionID,
"voidTransaction",
"<<AEFConst.CONFIG_ERROR, AEFConst.FACTORY_ERROR
*/
public int sendVoidSequence() throws AEFException
{
return sendVoidSequence(true);
}
/**
* Initialize the sub-state variables for ACE.
*
*/
private void initializeSubStates()
{
theMainSubState = Substate.getSubstate("SELECT_PROCEDURE");
}
/**
* Initialize the state variables for ACE.
*
*/
private void initializeStates()
{
// Get the values for all the ACE application states.
theIdState = State.getState("ID");
theOverrideState = State.getState("OVERRIDE");
theMainState = State.getState("ITEMENTRY");
theTenderCashingExchangeState = State.getState("TENDER_CASHING_EXCHANGE");
theCashierLoanPickupTenderCountState = State.getState("CASHIER_LOAN_PICKUP_TENDER_COUNT");
theTenderListState = State.getState("TENDER_LIST");
theTerminalTransferMonitorState = State.getState("TERMINAL_TRANSFER_MONITOR");
thePriceVerifyState = State.getState("PRICE_VERIFY_CHANGE");
}
/**
* Calls the Error Handler to try to clear an error.
*
* @return int Integer value representing the result of the key sequence.
* @exception AEFException
*/
public int handleError() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter ACEVoidTransactionActionImpl.handleError()");
log.trace(tempAEFMessage);
}
int retVal = -1;
AEFErrorHandler errorHandler = null;
args.clear();
args.put("SEQUENCE_ID", "clear-error");
theKeySequenceAction = (AEFAction)(actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args)));
AbstractPropertyCondition[] conditions =
{
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, theMainState),
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, theIdState),
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, theOverrideState)
};
theLock = new ConditionLock();
errorHandler = new AEFErrorHandler("There was an error in SAForcedLogoffActionImpl.sendClearSequence()");
retVal = errorHandler.handleError(theLock,
theKeySequenceAction,
conditions,
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout(),
retVal);
if (retVal < 0)
{
throw errorHandler.getAllExceptions();
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit ACEVoidTransactionActionImpl.handleError()");
log.trace(tempAEFMessage);
}
return retVal;
}
// Instance Variables
protected AEFAction theKeySequenceAction = null;
protected ConditionLock theLock = null;
protected boolean thePartialTransactionFlag = false;
protected String theMainSubState = null;
protected String theIdState = null;
protected String theOverrideState = null;
protected String theAcctOvrState = null;
protected String theMainState = null;
protected String theTenderCashingExchangeState = null;
protected String theCashierLoanPickupTenderCountState = null;
protected String theTenderListState = null;
protected String theTerminalTransferMonitorState = null;
protected String thePriceVerifyState = null;
protected static Vector theValidSubstates;
private static Log log = LogFactory.getLog(ACEVoidTransactionActionImpl.class);
}