/*******************************************************************************
* Copyright (c) 2012 OpenLegacy Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* OpenLegacy Inc. - initial API and implementation
*******************************************************************************/
package org.openlegacy.terminal.support;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openlegacy.OpenLegacyProperties;
import org.openlegacy.SessionProperties;
import org.openlegacy.SessionPropertiesProvider;
import org.openlegacy.exceptions.EntityNotAccessibleException;
import org.openlegacy.exceptions.EntityNotFoundException;
import org.openlegacy.exceptions.OpenLegacyRuntimeException;
import org.openlegacy.modules.SessionModule;
import org.openlegacy.support.AbstractEntitiesRegistry;
import org.openlegacy.support.AbstractSession;
import org.openlegacy.terminal.ConnectionProperties;
import org.openlegacy.terminal.ConnectionPropertiesProvider;
import org.openlegacy.terminal.ScreenEntity;
import org.openlegacy.terminal.ScreenEntityBinder;
import org.openlegacy.terminal.TerminalActionMapper;
import org.openlegacy.terminal.TerminalConnection;
import org.openlegacy.terminal.TerminalConnectionListener;
import org.openlegacy.terminal.TerminalField;
import org.openlegacy.terminal.TerminalSendAction;
import org.openlegacy.terminal.TerminalSession;
import org.openlegacy.terminal.TerminalSessionPropertiesConsts;
import org.openlegacy.terminal.TerminalSnapshot;
import org.openlegacy.terminal.actions.TerminalAction;
import org.openlegacy.terminal.definitions.ScreenEntityDefinition;
import org.openlegacy.terminal.exceptions.ScreenEntityNotAccessibleException;
import org.openlegacy.terminal.services.ScreenEntitiesRegistry;
import org.openlegacy.terminal.services.ScreensRecognizer;
import org.openlegacy.terminal.services.SessionNavigator;
import org.openlegacy.terminal.support.proxy.ScreenEntityMethodInterceptor;
import org.openlegacy.terminal.utils.ScreenEntityUtils;
import org.openlegacy.terminal.wait_conditions.WaitCondition;
import org.openlegacy.utils.ProxyUtil;
import org.openlegacy.utils.ReflectionUtil;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
/**
* A default session class exposes screenEntity building and sending
*
*
*/
public class DefaultTerminalSession extends AbstractSession implements TerminalSession, Serializable, ConnectionPropertiesProvider {
private static final long serialVersionUID = 1L;
@Inject
private List<ScreenEntityBinder> screenEntityBinders;
private TerminalConnection terminalConnection;
private ScreenEntity entity;
@Inject
private SessionNavigator sessionNavigator;
@Inject
private ScreensRecognizer screensRecognizer;
@Inject
private TerminalActionMapper terminalActionMapper;
@Inject
private ScreenEntitiesRegistry screenEntitiesRegistry;
@Inject
private ScreenEntityUtils screenEntityUtils;
@Inject
private SessionPropertiesProvider sessionPropertiesProvider;
@Inject
private OpenLegacyProperties openLegacyProperties;
private ScreenEntityMethodInterceptor interceptor;
private final static Log logger = LogFactory.getLog(DefaultTerminalSession.class);
private boolean useProxyForEntities = true;
private ConnectionProperties connectionProperties;
private SessionProperties sessionProperties;
@SuppressWarnings("unchecked")
public <S> S getEntity(Class<S> screenEntityClass, Object... keys) throws EntityNotFoundException {
checkRegistryDirty();
if (entity == null) {
entity = getEntityInner();
}
if (!screenEntityUtils.isEntitiesEquals(entity, screenEntityClass, keys)) {
resetEntity();
}
ScreenEntityDefinition definitions = screenEntitiesRegistry.get(screenEntityClass);
if (keys.length > definitions.getKeys().size()) {
throw (new EntityNotAccessibleException(
MessageFormat.format(
"Requested entity {0} with keys {1} doesnt matches the defined entity keys count: {2}. Verify key is defined for {3}",
screenEntityClass, ArrayUtils.toString(keys), definitions.getKeys().size(),
screenEntityClass.getName())));
}
if (entity == null) {
sessionNavigator.navigate(this, screenEntityClass, keys);
entity = getEntityInner();
}
return (S)entity;
}
private void checkRegistryDirty() {
if (screenEntitiesRegistry.isDirty()) {
resetEntity();
// set the registry back to clean - for design-time purposes only!
((AbstractEntitiesRegistry<?, ?>)screenEntitiesRegistry).setDirty(false);
}
}
private <S> ScreenEntity getEntityInner() {
resetEntity();
TerminalSnapshot terminalSnapshot = getSnapshot();
Class<?> matchedScreenEntity = screensRecognizer.match(terminalSnapshot);
if (matchedScreenEntity == null) {
return null;
}
ScreenEntity screenEntity = null;
if (useProxyForEntities) {
screenEntity = (ScreenEntity)ProxyUtil.createPojoProxy(matchedScreenEntity, ScreenEntity.class, interceptor);
} else {
screenEntity = (ScreenEntity)ReflectionUtil.newInstance(matchedScreenEntity);
}
ScreenEntityDefinition screenEntityDefinition = screenEntitiesRegistry.get(matchedScreenEntity);
if (screenEntityDefinition.isPerformDefaultBinding()) {
for (ScreenEntityBinder screenEntityBinder : screenEntityBinders) {
screenEntityBinder.populateEntity(screenEntity, terminalSnapshot);
}
}
List<ScreenEntityBinder> binders = screenEntityDefinition.getBinders();
if (binders != null) {
for (ScreenEntityBinder screenEntityBinder : binders) {
screenEntityBinder.populateEntity(screenEntity, terminalSnapshot);
}
}
return screenEntity;
}
private void resetEntity() {
if (entity != null) {
entity = null;
}
}
@SuppressWarnings("unchecked")
public <R extends ScreenEntity> R getEntity() {
checkRegistryDirty();
if (entity == null) {
entity = getEntityInner();
}
return (R)entity;
}
@SuppressWarnings("unchecked")
public <R extends ScreenEntity> R doAction(TerminalAction action, WaitCondition... waitConditions) {
return (R)doAction(action, null, waitConditions);
}
public <S extends ScreenEntity, R extends ScreenEntity> R doAction(TerminalAction terminalAction, S screenEntity,
Class<R> expectedEntity) {
try {
@SuppressWarnings("unchecked")
R object = (R)doAction(terminalAction, screenEntity);
return object;
} catch (ClassCastException e) {
throw (new ScreenEntityNotAccessibleException(e));
}
}
@SuppressWarnings("unchecked")
public <S extends ScreenEntity, R extends ScreenEntity> R doAction(TerminalAction terminalAction, S screenEntity,
WaitCondition... waitConditions) {
// verify screens are synch
if (screenEntity != null) {
getEntity(screenEntity.getClass());
}
resetEntity();
Object command = terminalActionMapper.getCommand(terminalAction);
if (command == null) {
terminalAction.perform(this, screenEntity);
} else {
SimpleTerminalSendAction sendAction = new SimpleTerminalSendAction(command);
if (screenEntity != null) {
ScreenEntityDefinition screenEntityDefinition = screenEntitiesRegistry.get(screenEntity.getClass());
if (screenEntityDefinition.isPerformDefaultBinding()) {
for (ScreenEntityBinder screenEntityBinder : screenEntityBinders) {
screenEntityBinder.populateSendAction(sendAction, getSnapshot(), screenEntity);
}
}
List<ScreenEntityBinder> binders = screenEntityDefinition.getBinders();
if (binders != null) {
for (ScreenEntityBinder screenEntityBinder : binders) {
screenEntityBinder.populateSendAction(sendAction, getSnapshot(), screenEntity);
}
}
}
doAction(sendAction, waitConditions);
}
return (R)getEntity();
}
private void notifyModulesBeforeConnect() {
Collection<? extends SessionModule> modulesList = getSessionModules().getModules();
for (SessionModule sessionModule : modulesList) {
if (sessionModule instanceof TerminalConnectionListener) {
((TerminalConnectionListener)sessionModule).beforeConnect(terminalConnection);
}
}
}
private void notifyModulesAfterConnect() {
Collection<? extends SessionModule> modulesList = getSessionModules().getModules();
for (SessionModule sessionModule : modulesList) {
if (sessionModule instanceof TerminalConnectionListener) {
((TerminalConnectionListener)sessionModule).afterConnect(terminalConnection);
}
}
}
protected void notifyModulesBeforeSend(TerminalSendAction terminalSendAction) {
Collection<? extends SessionModule> modulesList = getSessionModules().getModules();
for (SessionModule sessionModule : modulesList) {
if (sessionModule instanceof TerminalConnectionListener) {
((TerminalConnectionListener)sessionModule).beforeSendAction(terminalConnection, terminalSendAction);
}
}
}
protected void notifyModulesAfterSend() {
Collection<? extends SessionModule> modulesList = getSessionModules().getModules();
for (SessionModule sessionModule : modulesList) {
if (sessionModule instanceof TerminalConnectionListener) {
((TerminalConnectionListener)sessionModule).afterSendAction(terminalConnection);
}
}
}
public TerminalSnapshot getSnapshot() {
boolean newSession = false;
if (!terminalConnection.isConnected()) {
notifyModulesBeforeConnect();
newSession = true;
}
TerminalSnapshot snapshot = terminalConnection.getSnapshot();
if (newSession) {
notifyModulesAfterConnect();
}
return snapshot;
}
public Object getDelegate() {
return terminalConnection.getDelegate();
}
public void setTerminalConnection(TerminalConnection terminalConnection) {
this.terminalConnection = terminalConnection;
}
public void disconnect() {
List<? extends SessionModule> sessionModulesList = getSessionModules().getModules();
for (SessionModule sessionModule : sessionModulesList) {
sessionModule.destroy();
}
resetEntity();
terminalConnection.disconnect();
}
public boolean isConnected() {
return terminalConnection.isConnected();
}
public void setInterceptor(ScreenEntityMethodInterceptor interceptor) {
this.interceptor = interceptor;
}
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
interceptor.setTerminalSession(this);
}
public void doAction(TerminalSendAction sendAction, WaitCondition... waitConditions) {
doTerminalAction(sendAction, waitConditions);
}
private void performWait(WaitCondition... waitConditions) {
if (waitConditions == null || waitConditions.length == 0) {
return;
}
int totalWait = 0;
for (WaitCondition waitCondition : waitConditions) {
fetchSnapshot();
resetEntity();
while (waitCondition.continueWait(this) && totalWait < waitCondition.getWaitTimeout()) {
if (logger.isTraceEnabled()) {
logger.trace(MessageFormat.format("Waiting for {0}ms. Current screen is:{1}",
waitCondition.getWaitInterval(), fetchSnapshot()));
}
try {
Thread.sleep(waitCondition.getWaitInterval());
} catch (InterruptedException e) {
throw (new OpenLegacyRuntimeException(e));
}
totalWait += waitCondition.getWaitInterval();
fetchSnapshot();
resetEntity();
}
}
}
protected void doTerminalAction(TerminalSendAction sendAction, WaitCondition... waitConditions) {
formatSendAction(sendAction);
logScreenBefore(sendAction);
notifyModulesBeforeSend(sendAction);
terminalConnection.doAction(sendAction);
resetEntity();
performWait(waitConditions);
notifyModulesAfterSend();
logScreenAfter();
}
protected void formatSendAction(TerminalSendAction sendAction) {
List<TerminalField> fields = sendAction.getModifiedFields();
for (TerminalField terminalField : fields) {
if (openLegacyProperties.isUppercaseInput() || terminalField.isUppercase()) {
terminalField.setValue(terminalField.getValue().toUpperCase());
}
}
// sort the modified fields by position
Collections.sort(sendAction.getModifiedFields(), TerminalPositionContainerComparator.instance());
}
private void logScreenBefore(TerminalSendAction sendAction) {
if (logger.isDebugEnabled()) {
logger.debug(MessageFormat.format("\nAction:{0}, Cursor:{1}\n", sendAction.getCommand(),
sendAction.getCursorPosition()));
logger.debug("\nScreen before\n(* abc * marks a modified field, [ abc ] mark an input field, # mark cursor):\n\n"
+ getSnapshot());
}
}
protected void logScreenAfter() {
if (logger.isDebugEnabled()) {
logger.debug("\n\nScreen after ([ abc ] indicates a input field):\n\n" + getSnapshot());
}
}
public TerminalSnapshot fetchSnapshot() {
return terminalConnection.fetchSnapshot();
}
protected TerminalConnection getTerminalConnection() {
return terminalConnection;
}
protected ScreensRecognizer getScreensRecognizer() {
return screensRecognizer;
}
public Object getEntity(String entityName, Object... keys) throws EntityNotFoundException {
Class<?> entityClass = screenEntitiesRegistry.getEntityClass(entityName);
if (entityClass == null) {
throw (new EntityNotFoundException(MessageFormat.format("Screen entity \"{0}\" not found", entityName)));
}
return getEntity(entityClass, keys);
}
protected ScreenEntitiesRegistry getScreenEntitiesRegistry() {
return screenEntitiesRegistry;
}
public Integer getSequence() {
return terminalConnection.getSequence();
}
public <R extends ScreenEntity> void setEntity(R entity) {
this.entity = entity;
}
public boolean isUseProxyForEntities() {
return useProxyForEntities;
}
public void setUseProxyForEntities(boolean useProxyForEntities) {
this.useProxyForEntities = useProxyForEntities;
}
public void setSessionPropertiesProvider(SessionPropertiesProvider sessionPropertiesProvider) {
this.sessionPropertiesProvider = sessionPropertiesProvider;
}
public SessionProperties getProperties() {
if (sessionProperties == null) {
sessionProperties = sessionPropertiesProvider.getSessionProperties();
}
return sessionProperties;
}
public ConnectionProperties getConnectionProperties() {
if (connectionProperties == null) {
connectionProperties = new ConnectionProperties() {
public String getDeviceName() {
return (String)getProperties().getProperty(TerminalSessionPropertiesConsts.DEVICE_NAME);
}
};
}
return connectionProperties;
}
}