/* * ACEEPSCreditTenderActionImpl * * 9/3/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 java.rmi.RemoteException; import java.util.Vector; 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.CreditIdentifier; import com.ibm.retail.AEF.automation.DetectorAccess; import com.ibm.retail.AEF.automation.ItemIdentifier; import com.ibm.retail.AEF.automation.MSRCreditIdentifier; import com.ibm.retail.AEF.automation.ObjectDetector; import com.ibm.retail.AEF.automation.OrCondition; 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.automation.TenderIdentifier; import com.ibm.retail.AEF.automation.TenderMapperImpl; import com.ibm.retail.AEF.data.POSDeviceProperties; import com.ibm.retail.AEF.data.TransactionStatusProperties; import com.ibm.retail.AEF.data.WorkstationStatusProperties; import com.ibm.retail.AEF.event.AEFPropertyChangeEvent; import com.ibm.retail.AEF.event.AEFPropertyChangeListener; 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.AEFUtilities; import com.ibm.retail.AEF.util.BadConditionsImpl; import com.ibm.retail.si.util.AEFConst; import com.ibm.retail.si.util.AEFException; /** * ACEEPSCreditTenderActionImpl is a class which the POSAutomationProvider uses to accomplish * adding an EFT credit tender into a transaction on the POS application. * */ public class ACEEPSCreditTenderActionImpl extends ACEActionImpl implements AEFPropertyChangeListener { static String copyright() { return com.ibm.retail.si.Copyright.IBM_COPYRIGHT_SHORT; } private static Log log = LogFactory.getLog(ACEEPSCreditTenderActionImpl.class); /** * Constructor * * We assume that a non-null amount is provided and that the format of the * amount has been validated (i.e., numeric, with or without currency symbols). * * @param request The ActionRequest which contains a HashMap of arguments. * @exception com.ibm.retail.AEF.util.AEFException * AEFException return codes are: * <br>AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_TENDER_TYPE * */ public ACEEPSCreditTenderActionImpl(ActionRequest request) throws AEFException { super(request); if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter constructor of ACEEPSCreditTenderActionImpl."); log.trace(tempAEFMessage); } useTrackData = false; // validSubstates contains a list of all the substates for which // an item may be entered. This is a class static, so it is only // initialized once. // these are the only valid substates for credit tenders. Note that there // is an additional substate - EXPECTING_FOODSTAMP_TENDER - that will need // to be checked for foodstamp tenders if (validSubstates == null) { validSubstates = new Vector(); validSubstates.addElement(Substate.getSubstate("EXPECTING_ITEM")); validSubstates.addElement(Substate.getSubstate("EXPECTING_TENDER")); } tenderID = (TenderIdentifier)(request.getArguments()); amount = tenderID.getAmount(); // amount has already been validated // Strip out any non-numeric portion of the amount (currency symbol & decimal separator) amount = AEFUtilities.formatNumericOnly(amount); String cardType = null; if (tenderID instanceof CreditIdentifier) { creditID = (CreditIdentifier) (tenderID); accountNumber = creditID.getAccountNumber(); expDate = creditID.getExpirationDate(); cardType = creditID.getCardType(); } else if (tenderID instanceof MSRCreditIdentifier) { MSRCreditIdentifier msrCreditID = (MSRCreditIdentifier) (tenderID); track1Data = msrCreditID.getTrack1Data(); track2Data = msrCreditID.getTrack2Data(); track3Data = msrCreditID.getTrack3Data(); cardType = msrCreditID.getCardType(); useTrackData = true; } // Try to determine the tender variety if a card type was given. if (cardType != null && !cardType.equals(CreditIdentifier.UNKNOWN) && cardType != "") { // A card type was specified. Use the tender mapper to try to find out the // tender variety. String tenderKey = TenderMapperImpl.getInstance().getKey(cardType); if (tenderKey == null) { String tempString = "ACEEPSCreditTenderActionImpl(" + tenderID + "): Credit card type \"" + cardType + "\" doesn't match any tender description in tendermap.properties."; AEFException tempException = new AEFException(AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_TENDER_TYPE, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } else { tenderVariety = TenderMapperImpl.getInstance().getVariety(tenderKey); } } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit constructor of ACEEPSCreditTenderActionImpl."); 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 Tender instance. * @exception com.ibm.retail.AEF.util.AEFException * Among the possible AEFException error codes are: * <br>AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_TENDER_TYPE * <br>AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.ACCOUNT_TENDER_LIMIT * <br>AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.CHANGE_AMOUNT_LIMIT * <br>AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.NUMBER_OF_TENDERS_LIMIT * <br>AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.STAND_IN_COUNT_LIMIT * <br>AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.STAND_IN_AMOUNT_LIMIT * <br>AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.CARD_EXPIRED * <br>AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.TENDER_FLOOR_LIMIT * <br>AEFConst.PROCEDURE_NOT_ALLOWED, AEFConst.EXTERNAL_TENDER_AUTHORIZATION_SUSPENDED * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.TENDER_NOT_AUTHORIZED * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.RISK_1 * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.RISK_2 * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.RISK_3 * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.RISK_4 * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.VERIFICATION_TIMEOUT * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.CREDIT_NOT_AVAILABLE * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.TOO_LONG_IN_STANDIN * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.UNKNOWN_SERVICER * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.SERVICER_CLOSED * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.CARD_TYPE_UNKNOWN * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.TENDER_NOT_AUTHORIZED * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.PAYMENT_SYSTEM_OFFLINE * <br>AEFConst.TENDER_NOT_ACCEPTED, AEFConst.UNKNOWN_SERVICER * <br>AEFConst.INVALID_MANAGER_OVERRIDE_NUMBER * <br>AEFConst.KEYLOCK_ERROR, AEFConst.MANAGER_KEY_REQUIRED * <br>AEFConst.MSR_HOOK_SWIPE_ERROR, AEFConst.MSR_SET_TO_DECODE * <br>AEFConst.MSR_HOOK_SWIPE_ERROR, AEFConst.MSR_NOT_ENABLED * <br>AEFConst.JAVA_POS_EXCEPTION, see exception cause () for actual javaPos exception * <br>AEFConst.INVALID_ARGUMENT * <br><a href="../commonerrorcodes.html">Common Errors</a> */ public Object performAction() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEEPSCreditTenderActionImpl.performAction()"); log.trace(tempAEFMessage); } super.performAction(); // Call super to perform any common processing and clear any errors before we start. Object retVal = null; // If app 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 app is in one of the substates which is valid for item entry. //If not, throw exception. String currentSubstate = getCurrentSubstate(); if (validSubstates.contains(currentSubstate)) { // Application is in correct substate for tendering. // Check if we need to send the total first. if (currentSubstate.equals(Substate.getSubstate("EXPECTING_ITEM"))) { seqResult = sendTotalSequence(); } seqResult = sendTenderSequence(); if (seqResult==0) { // ENTER ACCOUNT NUMBER OVERRIDE OR CLEAR if (useTrackData) { seqResult = swipeMSR(track1Data, track2Data, track3Data); } else { seqResult = sendAccountNumberSequence(); } if (seqResult == 0) { // B309 APPROVED. // Success, wait for Tender // If we tendered out the transaction, we may get a // REMOVE RECEIPT FOR CUSTOMER message we have to handle. seqResult = waitForNextStateAfterTender(); retVal = waitForTender(); } // -999 is a special case for b048 throw exception if (seqResult == -999) { String tempString = "ACEEPSCreditTenderActionImpl.performAction(): Invalid account number. Account Number" + accountNumber + "Track 2 Data" + track2Data; AEFException tempException = new AEFException(AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_ACCOUNT_NUMBER, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } } } else { // Not in valid state for item entry. String tempString = "ACEEPSCreditTenderActionImpl.performAction(): POS application not in proper substate to tender credit.\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 ACEEPSCreditTenderActionImpl.performAction()"); log.trace(tempAEFMessage); } return retVal; } /** * Sends the "total" key sequence. * * * @return int An integer value representing the result of the key sequence. * @exception AEFException */ protected int sendTotalSequence() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEEPSCreditTenderActionImpl.sendTotalSequence()"); log.trace(tempAEFMessage); } int retVal = -1; args.clear(); args.put("SEQUENCE_ID", "total"); keySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); Condition goodConditions[] = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("EXPECTING_TENDER")), }; lock = new ConditionLock(); retVal = lock.performActionAndWait("wait-for-expecting-tender-substate", keySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout()); if (retVal < 0) { AEFErrorHandler errorHandler = new AEFErrorHandler("Send Total Sequence Error"); retVal = errorHandler.handleError(lock, keySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), retVal); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEEPSCreditTenderActionImpl.sendTotalSequence()"); log.trace(tempAEFMessage); } return retVal; } /** * Sends the key sequence for the credit tender amount. * * * @return int An integer value representing the result of the key sequence. * @exception com.ibm.retail.AEF.util.AEFException */ protected int sendTenderSequence() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEEPSCreditTenderActionImpl.sendTenderSequence()"); log.trace(tempAEFMessage); } int retVal = -1; args.clear(); StringBuffer sequenceIdBuf = new StringBuffer(); if (tenderVariety != null) { sequenceIdBuf.append("tenderVariety+"); args.put("%tenderVariety.0", tenderVariety); } sequenceIdBuf.append("creditAmount"); args.put("%creditAmount.0", amount); args.put("SEQUENCE_ID", new String(sequenceIdBuf)); keySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); Condition goodConditions[] = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("ACCT_NUMBER")), }; lock = new ConditionLock(); detector = ((DetectorAccess)(SessionContext.getSession())).getTenderDetector(); // Save any current tender instance number so we are sure to only get a tender // created after this key sequence is sent. instanceNumber = detector.getInstanceNumber(); retVal = lock.performActionAndWait("wait-for-account-number-guidance-prompt", keySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout()); if (retVal < 0) { AEFErrorHandler errorHandler = new AEFErrorHandler("Wait for account number state Error"); retVal = errorHandler.handleError(lock, keySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), retVal); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEEPSCreditTenderActionImpl.sendTenderSequence()"); log.trace(tempAEFMessage); } return retVal; } /** * Sends the account number for the credit tender. * * * @return int An integer value representing the result of the key sequence. * @exception AEFException */ protected int sendAccountNumberSequence() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEEPSCreditTenderActionImpl.sendAccountNumberSequence()"); log.trace(tempAEFMessage); } int retVal = -1; args.clear(); args.put("%0", accountNumber); args.put("SEQUENCE_ID", "accountNumber"); keySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); try { dataProvider.setPropertyValue(TransactionStatusProperties.CATEGORY, TransactionStatusProperties.LAST_CREDIT_APPROVED, "false"); dataProvider.addAEFPropertyChangeListener(this, POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE); } catch (RemoteException re) { /* Can't get here. */ } Condition goodConditions[] = { new PropertyEqualsCondition(TransactionStatusProperties.CATEGORY, TransactionStatusProperties.LAST_CREDIT_APPROVED, "true"), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("ACCOUNT_NUMBER_NEEDED")), }; Condition badConditions[] = BadConditionsImpl.getInstance().getExtendedBadConditions(); lock = new ConditionLock(); try { retVal = lock.performActionAndWait("wait-for-LAST-CREDIT-APPROVED", keySequenceAction, goodConditions, badConditions, getPaymentHostTimeout()); String currentSubstate = getCurrentSubstate(); boolean acctNumNeeded = false; acctNumNeeded = currentSubstate.equals(Substate.getSubstate("ACCOUNT_NUMBER_NEEDED")); if (acctNumNeeded) { sendClearSequence(true); retVal = -999; } else if (retVal < 0) { AEFErrorHandler errorHandler = new AEFErrorHandler("Send Account Number Sequence Error", creditID); retVal = errorHandler.handleError(lock, keySequenceAction, goodConditions, badConditions, getTimeout(), retVal); } } catch (AEFException e) { tempAEFMessage.setMessage("There was an AEF exception thrown in sendAccountNumberSequence of ACEEPSCreditTenderActionImpl."); log.error(tempAEFMessage, e); throw e; } finally { try { dataProvider.removeAEFPropertyChangeListener(this, POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE); } catch (RemoteException re) { /* Can't get here. */ } } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEEPSCreditTenderActionImpl.sendAccountNumberSequence()"); log.trace(tempAEFMessage); } return retVal; } /** * Sends credit data as if MSR swiped. * * * @return int An integer value representing the result of the key sequence. * @exception AEFException */ protected int swipeMSR(byte[] track1Data, byte[] track2Data, byte[] track3Data) throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEEPSCreditTenderActionImpl.swipeMSR()"); log.trace(tempAEFMessage); } int retVal = -1; args.clear(); args.put("TRACK1DATA", track1Data); args.put("TRACK2DATA", track2Data); args.put("TRACK3DATA", track3Data); keySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SwipeMSRAction", args))); try { dataProvider.setPropertyValue(TransactionStatusProperties.CATEGORY, TransactionStatusProperties.LAST_CREDIT_APPROVED, "false"); dataProvider.addAEFPropertyChangeListener(this, POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE); } catch (RemoteException re) { /* Can't get here. */ } Condition goodConditions[] = { new PropertyEqualsCondition(TransactionStatusProperties.CATEGORY, TransactionStatusProperties.LAST_CREDIT_APPROVED, "true"), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("ACCOUNT_NUMBER_NEEDED")), }; Condition badConditions[] = BadConditionsImpl.getInstance().getExtendedBadConditions(); lock = new ConditionLock(); try { retVal = lock.performActionAndWait("wait-for-LAST-CREDIT-APPROVED", keySequenceAction, goodConditions, badConditions, getPaymentHostTimeout()); String currentSubstate = getCurrentSubstate(); boolean acctNumNeeded = false; acctNumNeeded = currentSubstate.equals(Substate.getSubstate("ACCOUNT_NUMBER_NEEDED")); if (acctNumNeeded) { sendClearSequence(true); retVal = -999; } else if (retVal < 0) { AEFErrorHandler errorHandler = new AEFErrorHandler("Swipe MSR Error", tenderID); retVal = errorHandler.handleError(lock, keySequenceAction, goodConditions, badConditions, getTimeout(), retVal); } } catch (AEFException e) { tempAEFMessage.setMessage("There was an AEF exception thrown in swipeMSR() of ACEEPSCreditTenderActionImpl."); log.error(tempAEFMessage, e); throw e; } finally { try { dataProvider.removeAEFPropertyChangeListener(this, POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE); } catch (RemoteException re) { /* Can't get here. */ } } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEEPSCreditTenderActionImpl.swipeMSR()"); log.trace(tempAEFMessage); } return retVal; } /** * Waits for the next states after the tender was successful. This is necessary * because the transaction may have been tendered out, in which case we will * get a "REMOVE RECEIPT FOR CUSTOMER" prompt which must be cleared. * * * @return int An integer value representing the result of the key sequence. * @exception AEFException */ protected int waitForNextStateAfterTender() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEEPSCreditTenderActionImpl.waitForNextStateAfterTender()"); log.trace(tempAEFMessage); } int retVal = -1; Condition[] goodSubstates = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("SELECT_PROCEDURE")), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("EXPECTING_PROCEDURE")), }; Condition[] txnOverConditions = { new OrCondition(goodSubstates), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("MAIN")), new PropertyEqualsCondition(WorkstationStatusProperties.CATEGORY, WorkstationStatusProperties.SALES_TRANSACTION_IN_PROGRESS, "false"), }; Condition[] goodConditions = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("EXPECTING_TENDER")), new AndCondition(txnOverConditions), }; Condition[] removeReceiptCondition = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("REMOVE_CUSTOMER_RECEIPT")), }; Condition[] badConditions = BadConditionsImpl.getInstance().getBadConditions(removeReceiptCondition); lock = new ConditionLock(); retVal = lock.wait("wait-for-next-state-after-tender-accepted", goodConditions, badConditions, getTimeout(), true); if (retVal < 0) { AEFErrorHandler errorHandler = new AEFErrorHandler("After Tender Sequence Error"); retVal = errorHandler.handleError(lock, keySequenceAction, goodConditions, badConditions, getTimeout(), retVal); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEEPSCreditTenderActionImpl.waitForNextStateAfterTender()"); log.trace(tempAEFMessage); } return retVal; } /** * Waits for a new tender line item to be detected. * * * @return Object The newly detected tender. (Note in this case, it's an ArrayList that * contains the tender object). * @exception AEFException */ protected Object waitForTender() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEEPSCreditTenderActionImpl.waitForTender()"); log.trace(tempAEFMessage); } Object retVal = null; ObjectDetectorLock objLock = new ObjectDetectorLock(); retVal = objLock.waitForNewObject("wait-for-tender", detector, instanceNumber, getTimeout()); if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEEPSCreditTenderActionImpl.waitForTender()"); log.trace(tempAEFMessage); } return retVal; } /** * A AEF POSDataProvider property was updated. * We will be looking for a substate change to "APPROVED" * * @param evt contains details of the event * */ public void propertyChanged(AEFPropertyChangeEvent evt) { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEEPSCreditTenderActionImpl.propertyChanged()"); log.trace(tempAEFMessage); } // Because we only registered for substate events, this event must contain a substate value. String substate = (String)(evt.getNewValue()); if (substate.equals(Substate.getSubstate("TENDER_APPROVED"))) { // Credit was approved, set the POSDataProvider property. try { dataProvider.setPropertyValue(TransactionStatusProperties.CATEGORY, TransactionStatusProperties.LAST_CREDIT_APPROVED, "true"); } catch (RemoteException re) { /* Can't get here. */ } } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEEPSCreditTenderActionImpl.propertyChanged()"); log.trace(tempAEFMessage); } } /* Instance Variables */ protected CreditIdentifier creditID; protected TenderIdentifier tenderID; protected AEFAction keySequenceAction; protected ItemIdentifier itemID; protected ConditionLock lock; protected ObjectDetector detector; protected int instanceNumber; protected static Vector validSubstates; protected String amount; protected String accountNumber; protected String expDate; protected String tenderVariety; protected byte[] track1Data; protected byte[] track2Data; protected byte[] track3Data; protected boolean useTrackData; }