/* * ACEApplyDelayedCouponsActionImpl * * 07/22/2003 * * Copyright: * Licensed Materials - Property of IBM * "Restricted Materials of IBM" * 5724-AEF * (C) Copyright IBM Corp. 2003. * * ace/com/ibm/retail/AEF/action/ACEApplyDelayedCouponsActionImpl.java, aef.ace, aef.bravo 04/07/12 */ package com.ibm.retail.AEF.action; import java.util.ArrayList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.ibm.retail.AEF.automation.ActionRequest; import com.ibm.retail.AEF.automation.AndCondition; import com.ibm.retail.AEF.automation.Condition; import com.ibm.retail.AEF.automation.DetectorAccess; import com.ibm.retail.AEF.automation.ObjectDetector; import com.ibm.retail.AEF.automation.PropertyEqualsCondition; import com.ibm.retail.AEF.automation.State; import com.ibm.retail.AEF.automation.Substate; import com.ibm.retail.AEF.data.POSDeviceProperties; import com.ibm.retail.AEF.data.WorkstationStatusProperties; import com.ibm.retail.AEF.session.SessionContext; import com.ibm.retail.AEF.thread.ConditionLock; import com.ibm.retail.AEF.thread.ObjectDetectorLock; import com.ibm.retail.AEF.util.AEFErrorHandler; import com.ibm.retail.AEF.util.AEFPerfTrace; import com.ibm.retail.AEF.util.BadConditionsImpl; import com.ibm.retail.si.util.AEFConst; import com.ibm.retail.si.util.AEFException; /** * ACEApplyDelayedCouponsActionImpl is a class which the POSAutomationProvider uses to send * the <Total> sequence which causes delayed coupons to be applied. * This method should be called only once per transaction when all the items have been entered. * */ public class ACEApplyDelayedCouponsActionImpl 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. * */ public ACEApplyDelayedCouponsActionImpl(ActionRequest request) throws AEFException { super(request); if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter/-Exit constructor of ACEApplyDelayedCouponsActionImpl."); log.trace(tempAEFMessage); } } /** * Perform the action represented by the ActionRequest and return an ActionResult. * * * @param request The ActionRequest which contains the classname and arguments. * @return Object The Operator instance. * @exception AEFException * Among the possible error codes are: * <br>AEFConst.APPLICATION_NOT_IN_PROPER_STATE, AEFConst.APPLICATION_NOT_IN_PROPER_SUBSTATE */ public Object performAction() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEApplyDelayedCouponsActionImpl.performAction()"); log.trace(tempAEFMessage); } super.performAction(); // Call super to perform any common processing and clear any errors before we start. Object retVal = null; int seqResult = -1; String currentState = getCurrentState(); theDetector = ((DetectorAccess)(SessionContext.getSession())).getLineItemDetector(); // Check if we are in a clear state. // If so, clear the error. if (currentState.equals(State.getState("CLEAR"))) { sendClearSequence(true); currentState = getCurrentState(); } theCurrentSubstate = getCurrentSubstate(); // Check precondition that POS_SUB_STATE is "EXPECTING_ITEM" substate (1001). // If not, throw exception. if (!theCurrentSubstate.equals(Substate.getSubstate("EXPECTING_ITEM"))) { // Not in valid state for applyDelayedCoupons. String tempString = "ACEApplyDelayedCouponsActionImpl.performAction(): POS application not in proper substate to apply delayed coupons.\n Expected substate " + Substate.getSubstate("EXPECTING_ITEM") + ", but application is in state " + currentState + "."; AEFException tempException = new AEFException(AEFConst.APPLICATION_NOT_IN_PROPER_STATE, AEFConst.APPLICATION_NOT_IN_PROPER_SUBSTATE, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } else { // Application is in correct state to send the total key. seqResult = sendApplyDelayedCouponsSequence(); if (seqResult==0) { retVal = waitForCoupons(); } } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEApplyDelayedCouponsActionImpl.performAction()"); log.trace(tempAEFMessage); } return retVal; } /** * Sends the key sequence for applying delayed coupons. * * * @return int 0 = success, * @exception AEFException */ public int sendApplyDelayedCouponsSequence() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEApplyDelayedCouponsActionImpl.sendApplyDelayedCouponsSequence()"); log.trace(tempAEFMessage); } int retVal = -1; args.clear(); args.put("SEQUENCE_ID", "applyDelayedCoupons"); theKeySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); Condition[] andConditions = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("MAIN")), // substate is coming in AFTER the unit of work, uow gets a True, then a False so // by the time we get the substate and check, it is no longer True. /*new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("EXPECTING_TENDER")), */ new PropertyEqualsCondition(WorkstationStatusProperties.CATEGORY, WorkstationStatusProperties.UNIT_OF_WORK, "true") }; Condition[] goodConditions = { new AndCondition( andConditions ), }; Condition andConds2[] = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("MAIN")), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("EXPECTING_TENDER")), }; Condition goodConditions2[] = { new AndCondition(andConds2) }; theLock = new ConditionLock(); // Save any current line item instance number so we are sure to only get line items // created after this key sequence is sent. theInstanceNumber = theDetector.getInstanceNumber(); if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "applyDelayedCoupons", ">>>Sending apply delayed coupon 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 Apply Delayed Coupons Sequence Error"); retVal = errorHandler.handleError(theLock, theKeySequenceAction, goodConditions2, BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), retVal); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEApplyDelayedCouponsActionImpl.sendApplyDelayedCouponsSequence()"); log.trace(tempAEFMessage); } return retVal; } /** * Wait for any delayed coupons to be detected. * * * @return ArrayList An array of LineItems created by the action. * @exception AEFException */ public ArrayList waitForCoupons() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEApplyDelayedCouponsActionImpl.waitForCoupons()"); log.trace(tempAEFMessage); } ArrayList retVal = null; ObjectDetectorLock objLock = new ObjectDetectorLock(); // Note: We don't do the typical wait because we may not get any line items. // Since we have already waited for the unit of work, we will only wait 1 ms for the line // items, since they should already have been detected. try { retVal = (ArrayList)(objLock.waitForNewObject("wait-for-coupon-array",theDetector, theInstanceNumber, 1, true)); } catch (AEFException e) { // This should never happen since we are ignoring timeout in waitForNewObject call - d 6098 if (e.getErrorCode() == AEFConst.OPERATION_TIMEOUT) { // This is normal. retVal = null; } else { throw e; } } if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "applyDelayedCoupons", ">>>Apply delayed coupon key sequence processed by application."); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEApplyDelayedCouponsActionImpl.waitForCoupons()"); log.trace(tempAEFMessage); } return retVal; } /* Instance Variables */ protected AEFAction theKeySequenceAction; protected ConditionLock theLock; protected ObjectDetector theDetector; protected int theInstanceNumber; protected String theCurrentSubstate; private static Log log = LogFactory.getLog(ACEItemEntryActionImpl.class); }