/*
* SACustomerEntryActionImpl
*
* 10/18/2002
*
* 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;
/**
* SACustomerEntryActionImpl is a class which the POSAutomationProvider uses to
* add a customer entry to a transaction on the POS application.
*
*/
public class SACustomerEntryActionImpl extends SAActionImpl
{
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
*/
public SACustomerEntryActionImpl(ActionRequest request) throws AEFException
{
super(request);
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.SACustomerEntryActionImpl().");
log.trace(tempAEFMessage);
}
// theValidSubstates contains a list of all the substates for which
// a customer may be entered. This is a class static, so it is only
// initialized once.
if (theValidSubstates == null)
{
theValidSubstates = new Vector();
theValidSubstates.addElement(Substate.getSubstate("SELECT_PROCEDURE"));
theValidSubstates.addElement(Substate.getSubstate("EXPECTING_ITEM"));
theValidSubstates.addElement(Substate.getSubstate("TRANS_TOTALLED"));
theValidSubstates.addElement(Substate.getSubstate("CHANGE_OR_BAL_DUE"));
theValidSubstates.addElement(Substate.getSubstate("TRAINING_MODE"));
}
LoyaltyIdentifier loyaltyId = (LoyaltyIdentifier)(request.getArguments());
theCustomerId = loyaltyId.getID();
theIDType = loyaltyId.getType();
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit SACustomerEntryActionImpl.SACustomerEntryActionImpl().");
log.trace(tempAEFMessage);
}
}
/**
* Perform the action represented by the ActionRequest and return an ActionResult.
*
* @return Object The Customer instance.
* @exception AEFException
* Among the possible error codes are:
*
AEFConst.APPLICATION_NOT_IN_PROPER_STATE, AEFConst.NONE
*
AEFConst.UNSUPPORTED_OPERATION, AEFCONST.NONE
*/
public Object performAction() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.performAction().");
log.trace(tempAEFMessage);
}
// SA base EM does not support alternate ID, so we need to check for that.
if (theIDType.equalsIgnoreCase(LoyaltyIdentifier.ALTERNATE_TYPE))
{
String tempString = "SACustomerEntryActionImpl.performAction(): Base EM does not support alternate loyalty ids.";
AEFException tempException = new AEFException(AEFConst.UNSUPPORTED_OPERATION, AEFConst.NONE, tempString);
tempAEFMessage.setMessage(tempString);
log.error(tempAEFMessage, tempException);
throw tempException;
}
super.performAction(); // Call super to perform any common processing and clear any errors before we start.
Object retVal = null;
// If application is in secured state, and options are set to automatically do a
// special signon, then create the logon action to do the special signon first.
checkForSpecialSignon();
int seqResult = -1;
// Check precondition that the application is in one of the substates which
// is valid for customer entry. If not, then throw an exception.
String currentSubstate = getCurrentSubstate();
AEFSession session = SessionContext.getSession();
theDetector = ((DetectorAccess) (session)).getCustomerEntryDetector();
if (theValidSubstates.contains(currentSubstate))
{
try
{
SalesTransaction trans = (SalesTransaction)(session.getPOSAutomationProvider().getTransaction());
if (log.isDebugEnabled())
{
tempAEFMessage.setMessage("Current state = EXPECTING_ITEM" + currentSubstate.equals(Substate.getSubstate("EXPECTING_ITEM")));
log.debug(tempAEFMessage);
tempAEFMessage.setMessage("Customer = " + trans.getCustomer());
log.debug(tempAEFMessage);
tempAEFMessage.setMessage("Trans has items = " + trans.hasItems());
log.debug(tempAEFMessage);
}
// If current substate is EXPECTING_ITEM, and there is already a customer and
// there are unvoided items in the transaction, we have to send a TOTAL first.
if (currentSubstate.equals(Substate.getSubstate("EXPECTING_ITEM")) &&
trans.getCustomer() != null &&
trans.hasItems())
{
seqResult = sendTotalSequence();
}
}
catch (RemoteException re)
{
// Can't get here.
tempAEFMessage.setMessage("There was a remote exception thrown in performAction of SACustomerEntryActionImpl.");
log.error(tempAEFMessage, re);
}
// In a valid state for customer number entry
seqResult = sendCustomerEntrySequence();
if (log.isDebugEnabled())
{
tempAEFMessage.setMessage("SACustomerEntryActionImpl.performAction seqResult = " + seqResult);
log.debug(tempAEFMessage);
}
if (seqResult >= 0)
{
// Successfully entered customer number.
retVal = waitForCustomer();
}
}
else
{
// Not in valid state for customer number entry
String tempString = "SACustomerEntryActionImpl.performAction(): POS application not in proper state to perform customer entry.\n Application substate is " + currentSubstate + ".";
AEFException tempException = new AEFException(AEFConst.APPLICATION_NOT_IN_PROPER_STATE, 0, tempString);
tempAEFMessage.setMessage(tempString);
log.error(tempAEFMessage, tempException);
throw tempException;
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit SACustomerEntryActionImpl.performAction().");
log.trace(tempAEFMessage);
}
return retVal;
}
/**
* Sends the key sequence which will cause the customer number to be entered.
*
* @return int An integer value representing the result of the key sequence.
* @exception AEFException
* Among the possible error codes are:
*
AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_LOYALTY_NUMBER
*/
public int sendCustomerEntrySequence() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.sendCustomerEntrySequence().");
log.trace(tempAEFMessage);
}
int retVal = -1;
// if all zeroes then an invalid argument.
boolean nonZeroString = false;
for (int i= 0; i < theCustomerId.length(); i++)
{
if (theCustomerId.charAt(i) != '0')
{
nonZeroString = true;
}
}
if (! nonZeroString)
{
String tempString = "SACustomerEntryActionImpl.sendCustomerEntrySequence(): Invalid argument " + theCustomerId + ".";
AEFException tempException = new AEFException(AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_LOYALTY_NUMBER, tempString);
tempAEFMessage.setMessage(tempString);
log.error(tempAEFMessage, tempException);
throw tempException;
}
args.clear();
args.put("%0", theCustomerId);
if (theIDType != null && theIDType.equals(LoyaltyIdentifier.ALTERNATE_TYPE))
{
args.put("SEQUENCE_ID", "alternateCustomer");
}
else
{
args.put("SEQUENCE_ID", "customer");
}
theKeySequenceAction = (AEFAction)
(actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args)));
Condition[] goodConditions =
{
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE,
Substate.getSubstate("EXPECTING_ITEM")),
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE,
Substate.getSubstate("SELECT_PROCEDURE")),
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE,
Substate.getSubstate("CHANGE_OR_BAL_DUE"))
};
theLock = new ConditionLock();
// Save any current customer instance number so we are sure to only get an operator
// created after this key sequence is sent.
theInstanceNumber = theDetector.getInstanceNumber();
if (perfTrace.isEnabled(AEFPerfTrace. COARSE))
{
perfTrace.reportTimer(AEFPerfTrace. COARSE,
sessionID,
"addCustomer",
">>>Sending customer id key sequence to application.");
}
retVal = theLock.performActionAndWait("wait-for-expecting-item-substate",
theKeySequenceAction,
goodConditions,
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout());
if (retVal < 0)
{
AEFErrorHandler errorHandler = new AEFErrorHandler("Send Customer Entry Sequence Error");
retVal = errorHandler.handleError(theLock,
theKeySequenceAction,
goodConditions,
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout(),
retVal);
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit SACustomerEntryActionImpl.sendCustomerEntrySequence().");
log.trace(tempAEFMessage);
}
return retVal;
}
/**
* Sends the total key sequence.
*
* @return int An integer value representing the result of the key sequence.
* @exception AEFException
*/
public int sendTotalSequence() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.sendTotalSequence().");
log.trace(tempAEFMessage);
}
int retVal = -1;
args.clear();
args.put("SEQUENCE_ID", "total");
theKeySequenceAction = (AEFAction)
(actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args)));
Condition[] goodConditions =
{
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE,
Substate.getSubstate("TRANS_TOTALLED")),
};
theLock = new ConditionLock();
if (perfTrace.isEnabled(AEFPerfTrace. COARSE))
{
perfTrace.reportTimer(AEFPerfTrace. COARSE,
sessionID,
"addCustomer",
">>>Sending customer id key sequence to application.");
}
retVal = theLock.performActionAndWait("wait-for-trans-totalled-substate",
theKeySequenceAction,
goodConditions,
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout());
if (retVal < 0)
{
AEFErrorHandler errorHandler = new AEFErrorHandler("Send Customer Entry TOTAL Sequence Error");
retVal = errorHandler.handleError(theLock,
theKeySequenceAction,
goodConditions,
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout(),
retVal);
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit SACustomerEntryActionImpl.sendTotalSequence().");
log.trace(tempAEFMessage);
}
return retVal;
}
/**
* Waits for customer to be entered
*
* @return Customer The customer created by the action.
* @exception AEFException
*/
public Customer waitForCustomer() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.waitForCustomer().");
log.trace(tempAEFMessage);
}
Customer retVal = null;
// Successfully entered customer. Wait for the operator object to be created.
ObjectDetectorLock objLock = new ObjectDetectorLock();
retVal = (Customer) (objLock.waitForNewObject("wait-for-customer-entry", theDetector,
theInstanceNumber, getTimeout()));
if (perfTrace.isEnabled(AEFPerfTrace. COARSE))
{
perfTrace.reportTimer(AEFPerfTrace. COARSE,
sessionID,
"addCustomer",
"<<