package org.marketcetera.photon.internal.strategy.engine.sa; import java.util.Iterator; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; import org.marketcetera.photon.commons.ExceptionUtils; import org.marketcetera.photon.commons.Validate; import org.marketcetera.photon.core.ICredentials; import org.marketcetera.photon.core.ICredentialsService; import org.marketcetera.photon.core.ICredentialsService.IAuthenticationHelper; import org.marketcetera.photon.core.ILogoutService; import org.marketcetera.photon.module.ISinkDataManager; import org.marketcetera.photon.strategy.engine.model.core.ConnectionState; import org.marketcetera.photon.strategy.engine.model.sa.StrategyAgentEngine; import org.marketcetera.photon.strategy.engine.model.sa.impl.StrategyAgentEngineImpl; import org.marketcetera.photon.strategy.engine.sa.StrategyAgentEngines; import org.marketcetera.saclient.ConnectionException; import org.marketcetera.saclient.ConnectionStatusListener; import org.marketcetera.saclient.DataReceiver; import org.marketcetera.saclient.SAClient; import org.marketcetera.saclient.SAClientFactory; import org.marketcetera.saclient.SAClientParameters; import org.marketcetera.saclient.rpc.SAClientContextClassProvider; import org.marketcetera.util.misc.ClassVersion; /* $License$ */ /** * Internal engine implementation. See * {@link StrategyAgentEngines#createStrategyAgentEngine(StrategyAgentEngine, ExecutorService, ICredentialsService, ILogoutService)} * . * * @author <a href="mailto:will@marketcetera.com">Will Horn</a> * @version $Id: InternalStrategyAgentEngine.java 10795 2009-10-06 20:05:38Z * will $ * @since 2.0.0 */ @ClassVersion("$Id: InternalStrategyAgentEngine.java 16879 2014-04-15 21:40:25Z colin $") public class InternalStrategyAgentEngine extends StrategyAgentEngineImpl { private final ExecutorService mGUIExecutor; private final ICredentialsService mCredentialsService; private final SAClientFactory mClientFactory; private final ILogoutService mLogoutService; private final ISinkDataManager mSinkDataManager; private final Runnable mLogoutRunnable = new Runnable() { @Override public void run() { try { disconnect(); } catch (Exception e) { Messages.INTERNAL_STRATEGY_AGENT_ENGINE_DISCONNECT_ON_LOGOUT_FAILED .error(InternalStrategyAgentEngine.this, e, getName()); } } }; private final AtomicReference<SAClient> mClient = new AtomicReference<SAClient>(); /** * Constructor. * * @param engine the desired engine configuration * @param guiExecutor the executor to run tasks that change the model state * @param credentialsService the service to use to authenticate connections * @param logoutService the service used to disconnect remote connections on logout * @param factory the SAClient factory * @param sinkDataManager manager to send data received from remote agent, may be null to ignore data * @throws IllegalArgumentException if engine, guiExecutor, credentialsService, logoutService, or factory is null */ public InternalStrategyAgentEngine(StrategyAgentEngine engine, ExecutorService guiExecutor, ICredentialsService credentialsService, ILogoutService logoutService, SAClientFactory factory, ISinkDataManager sinkDataManager) { Validate.notNull(engine, "engine", //$NON-NLS-1$ guiExecutor, "guiExecutor", //$NON-NLS-1$ credentialsService, "credentialsService", //$NON-NLS-1$ logoutService, "logoutService", //$NON-NLS-1$ factory, "factory"); //$NON-NLS-1$ mGUIExecutor = guiExecutor; mCredentialsService = credentialsService; mLogoutService = logoutService; mClientFactory = factory; mSinkDataManager = sinkDataManager; setName(engine.getName()); setDescription(engine.getDescription()); setJmsUrl(engine.getJmsUrl()); setWebServiceHostname(engine.getWebServiceHostname()); setWebServicePort(engine.getWebServicePort()); } @Override public void connect() throws Exception { final AtomicReference<ConnectionException> exception = new AtomicReference<ConnectionException>(); if (!mCredentialsService.authenticateWithCredentials(new IAuthenticationHelper() { @Override public boolean authenticate(ICredentials credentials) { try { SAClient client = mClientFactory.create(new SAClientParameters(credentials.getUsername(), credentials.getPassword().toCharArray(), getJmsUrl(), getWebServiceHostname(), getWebServicePort(), SAClientContextClassProvider.INSTANCE)); client.start(); mClient.set(client); return true; } catch (ConnectionException e) { exception.set(e); return false; } } })) { if (exception.get() != null) { throw exception.get(); } else { return; } } SAClient client = mClient.get(); client.addConnectionStatusListener(new ConnectionStatusListener() { @Override public void receiveConnectionStatus(boolean inStatus) { if (!inStatus) { try { disconnect(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }); if (mSinkDataManager != null) { client.addDataReceiver(new DataReceiver() { @Override public void receiveData(Object inObject) { mSinkDataManager.sendData(getName(), inObject); } }); } mLogoutService.addLogoutRunnable(mLogoutRunnable); final StrategyAgentConnection newConnection = new StrategyAgentConnection( client, mGUIExecutor); ExceptionUtils.launderedGet(mGUIExecutor.submit(new Runnable() { @Override public void run() { setConnection(newConnection); setConnectionState(ConnectionState.CONNECTED); } })); // pull remote state newConnection.refresh(); } @Override public void disconnect() throws InterruptedException { SAClient client = mClient.getAndSet(null); if (client == null) { return; } client.close(); mLogoutService.removeLogoutRunnable(mLogoutRunnable); ExceptionUtils.launderedGet(mGUIExecutor.submit(new Runnable() { @Override public void run() { setConnection(null); setConnectionState(ConnectionState.DISCONNECTED); /* * Cannot call getDeployedStrategies().clear() due to Eclipse * bug. See note on StrategyEngine#getDeployedStrategies(). */ for (Iterator<?> iterator = getDeployedStrategies().iterator(); iterator .hasNext();) { iterator.next(); iterator.remove(); } } })); } }