/* * SALogonActionImpl * * 07/29/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; /** * SALogonActionImpl is a class which the POSAutomationProvider uses to accomplish * a logon onto the SA application. * */ public class SALogonActionImpl 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 SALogonActionImpl(ActionRequest request) throws AEFException { super(request); if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SALogonActionImpl.SALogonActionImpl()."); log.trace(tempAEFMessage); } if (sessionID == null) { sessionID = "999"; } OperatorIdentifier opId = (OperatorIdentifier)(request.getArguments()); id = opId.getID(); password = opId.getPassword(); newPassword = opId.getNewPassword(); if (id == null || id.length() == 0) { id = AppLogons.getID(sessionID); } if (password == null || password.length() == 0) { password = AppLogons.getPassword(sessionID); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SALogonActionImpl.SALogonActionImpl()."); 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.INVALID_ARGUMENT, AEFConst.NEW_PASSWORD_PROHIBITED * <br>AEFConst.APPLICATION_NOT_IN_PROPER_STATE */ public Object performAction() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SALogonActionImpl.performAction()."); log.trace(tempAEFMessage); } super.performAction(); // Call super to perform any common processing and clear any errors before we start. if (newPassword != null && newPassword.length() > 0) { String tempString = "SALogonActionImpl.performAction(): Change password function not implemented."; AEFException tempException = new AEFException(AEFConst.INVALID_ARGUMENT, AEFConst.NEW_PASSWORD_PROHIBITED, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } Object retVal = null; int seqResult = -1; String currentState = getCurrentState(); detector = ((DetectorAccess)(SessionContext.getSession())).getOperatorDetector(); idState = State.getState("ID"); passwordState = State.getState("PASSWORD"); itemEntryState = State.getState("ITEMENTRY"); securedSignoffState = State.getState("SECURED"); // Check if we are in a clear state. This could be a B014 NO TRANSACTION RECOVERY // for example. If so, clear the error. if (currentState.equals(State.getState("CLEAR"))) { sendClearSequence(true); currentState = getCurrentState(); } if (currentState.equals(securedSignoffState)) { // An operator is already signed on. retVal = doSecuredSignon(); } //Check precondition that POS_STATE is "ID" state (2). If not, throw exception. else if (!currentState.equals(idState)) { // Not in valid state for signon. String tempString = "SALogonActionImpl.performAction(): POS application not in proper state to perform logon.\n Expected state " + idState + ", but application is in state " + currentState + "."; AEFException tempException = new AEFException(AEFConst.APPLICATION_NOT_IN_PROPER_STATE, 0, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } else { // Application is in correct state to start preforming the logon. seqResult = sendIDSequence(); if (seqResult==0) { // Successfully got to password state, send the password sequence. seqResult = sendPasswordSequence(); if (seqResult == 0 || seqResult == 1) { Operator operator = null; operator = waitForOperator(); retVal = operator; try { operator.getInfo().setPassword(password); } catch (RemoteException re) { // Can't get here. tempAEFMessage.setMessage("There was a remote exception thrown in SALogonActionImpl.performAction()."); log.error(tempAEFMessage, re); } } } } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SALogonActionImpl.performAction()."); log.trace(tempAEFMessage); } return retVal; } /** * Sends the key sequence for entering the operator id. * * * @return int 0 = success, * @exception AEFException * Among the possible error codes are: * <br>AEFConst.CONFIG_ERROR, AEFConst.NO_DEFAULT_ID_CONFIGURED */ public int sendIDSequence() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SALogonActionImpl.sendIDSequence()."); log.trace(tempAEFMessage); } int retVal = -1; if ( id == null || id.length() == 0) { // Error, unable to lookup default id for terminal number. String tempString = "SALogonActionImpl: Default ID and/or password not configured for terminal " + sessionID + ", unable to perform logon.\nSee applogon.properties for id/password configuration."; AEFException tempException = new AEFException(AEFConst.CONFIG_ERROR, AEFConst.NO_DEFAULT_ID_CONFIGURED, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } args.clear(); args.put("%0", id); args.put("SEQUENCE_ID", "id"); keySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); Condition[] goodConditions = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, passwordState), // 0 = success }; lock = new ConditionLock(); // Save any current operator instance number so we are sure to only get an operator // created after this key sequence is sent. instanceNumber = detector.getInstanceNumber(); retVal = lock.performActionAndWait("wait-for-password-state", keySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout()); if (retVal < 0) { AEFErrorHandler errorHandler = new AEFErrorHandler("Send Signon ID Sequence Error"); retVal = errorHandler.handleError(lock, keySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), retVal); } if (log.isDebugEnabled()) { tempAEFMessage.setMessage("SALogonActionImpl.sendIDSequence() returning : " + retVal); log.debug(tempAEFMessage); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SALogonActionImpl.sendIDSequence()."); log.trace(tempAEFMessage); } return retVal; } /** * Sends the key sequence for entering the operator password. * * * @return int 0,1 = success * @exception AEFException * Among the possible error codes are: * <br>AEFConst.CONFIG_ERROR, AEFConst.NO_DEFAULT_ID_CONFIGURED */ public int sendPasswordSequence() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SALogonActionImpl.sendPasswordSequence()."); log.trace(tempAEFMessage); } int retVal = -1; if ( password == null || password.length() == 0) { // Error, unable to lookup default password for terminal number. AEFException ex = new AEFException(AEFConst.CONFIG_ERROR, AEFConst.NO_DEFAULT_ID_CONFIGURED, "SALogonActionImpl: Default ID and/or password not configured for terminal " + sessionID + ", unable to perform logon.\nSee applogon.properties for id/password configuration."); try { sendClearSequence(); } catch (AEFException e) { // Ignore any errors from sending the clear. } tempAEFMessage.setMessage("SALogonActionImpl: Default ID and/or password not configured for terminal " + sessionID + ", unable to perform logon.\nSee applogon.properties for id/password configuration."); log.error(tempAEFMessage, ex); throw ex; } // We have a password which we can use to attempt the secure mode signon. args.clear(); args.put("%0", password); args.put("SEQUENCE_ID", "password"); keySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); 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 andConds2[] = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("MAIN")), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("CHANGE_OR_BAL_DUE")) }; Condition goodConditions[] = { new AndCondition(andConds1), new AndCondition(andConds2) }; if (lock == null) { lock = new ConditionLock(); } if (log.isDebugEnabled()) { tempAEFMessage.setMessage("About to wait on the perform action for 'password'"); log.debug(tempAEFMessage); } if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "logon", ">>>Sending logon password key sequence to application."); } retVal= lock.performActionAndWait("wait-for-item-entry-state", keySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout()); if (retVal < 0) { AEFErrorHandler errorHandler = new AEFErrorHandler("Send Signon Password Sequence Error"); retVal = errorHandler.handleError(lock, keySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), retVal); } if (log.isDebugEnabled()) { tempAEFMessage.setMessage(" Condition returned was " + retVal); log.debug(tempAEFMessage); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SALogonActionImpl.sendPasswordSequence()."); log.trace(tempAEFMessage); } return retVal; } /** * Blocks the calling thread until a new operator object is created. * * * @exception AEFException */ public Operator waitForOperator() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SALogonActionImpl.waitForOperator()."); log.trace(tempAEFMessage); } Operator retVal = null; // Successfully got to item entry. Wait for the operator object to be created. ObjectDetectorLock objLock = new ObjectDetectorLock(); retVal = (Operator)(objLock.waitForNewObject("wait-for-operator",detector, instanceNumber, getTimeout())); if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "logon", "<<<Detected operator logon from application."); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SALogonActionImpl.waitForOperator()."); log.trace(tempAEFMessage); } return retVal; } /** * Performs the logic required to sign an operator on from secured mode. * * * @exception AEFException * Among the possible error codes are: * <br>AEFConst.PROCEDURE_NOT_ALLOWED, AEFConst.ANOTHER_OPERATOR_SIGNED_ON */ public Operator doSecuredSignon() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SALogonActionImpl.doSecuredSignon()."); log.trace(tempAEFMessage); } if (log.isDebugEnabled()) { tempAEFMessage.setMessage("App in secured signoff state."); log.debug("App in secured signoff state."); } Operator operator = null; // Somebody is already signed on, check to see if the id of the new signon request // matches the id of the already signed on operator. try { operator = automationProvider.getOperator(); if (operator!=null && !operator.getInfo().getID().equals(id)) { // Currently signed on operator is a different operator. String tempString = "SALogonActionImpl.performAction(): Can't perform logon for operator " + id + " because operator " + operator.getInfo().getID() + " is already signed on."; AEFException tempException = new AEFException(AEFConst.PROCEDURE_NOT_ALLOWED, AEFConst.ANOTHER_OPERATOR_SIGNED_ON, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } else if (operator != null) { // The requested operator is already signed on, but app is in secured // signoff mode, just need to send password sequence. // Use the password of the currently signed on operator if possible. String pwd = operator.getInfo().getPassword(); if (pwd != null && pwd.length() > 0) { password = pwd; } int seqResult = sendPasswordSequence(); if (seqResult == 0 || seqResult == 1) { operator = waitForOperator(); try { operator.getInfo().setPassword(password); } catch (RemoteException re) { // Can't get here. tempAEFMessage.setMessage("There was a remote exception thrown in SALogonActionImpl.doSecuredSignon()."); log.error(tempAEFMessage, re); } } } } catch (RemoteException re) { // Not expected to get here since we are calling locally. tempAEFMessage.setMessage("There was a remote exception thrown in SALogonActionImpl.doSecuredSignon()."); log.error(tempAEFMessage, re); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SALogonActionImpl.doSecuredSignon()."); log.trace(tempAEFMessage); } return operator; } /* Instance Variables */ protected AEFAction keySequenceAction; protected String id; protected String password; protected String newPassword; protected ConditionLock lock; protected ObjectDetector detector; protected int instanceNumber; protected String idState; protected String passwordState; protected String itemEntryState; protected String securedSignoffState; private static Log log = LogFactory.getLog(SALogonActionImpl.class); }