package org.marketcetera.photon.internal.strategy.engine.sa;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import javax.annotation.concurrent.NotThreadSafe;
import org.marketcetera.module.ModuleURN;
import org.marketcetera.photon.commons.Validate;
import org.marketcetera.photon.strategy.engine.AbstractStrategyEngineConnection;
import org.marketcetera.photon.strategy.engine.model.core.DeployedStrategy;
import org.marketcetera.photon.strategy.engine.model.core.Strategy;
import org.marketcetera.photon.strategy.engine.model.core.StrategyEngineConnection;
import org.marketcetera.saclient.ConnectionException;
import org.marketcetera.saclient.CreateStrategyParameters;
import org.marketcetera.saclient.SAClient;
import org.marketcetera.util.log.I18NMessage2P;
import org.marketcetera.util.misc.ClassVersion;
import org.marketcetera.util.ws.wrappers.RemoteProperties;
import com.google.common.collect.Maps;
/* $License$ */
/**
* Adapts {@link SAClient} to {@link StrategyEngineConnection}.
* <p>
* This class is not fully thread safe. It does manage visibility of the model
* objects by ensuring all updates are done using the guiExecutor. However, it
* does not support concurrent access.
*
* @author <a href="mailto:will@marketcetera.com">Will Horn</a>
* @version $Id: StrategyAgentConnection.java 16161 2012-07-16 20:27:32Z colin $
* @since 2.0.0
*/
@NotThreadSafe
@ClassVersion("$Id: StrategyAgentConnection.java 16161 2012-07-16 20:27:32Z colin $")
public class StrategyAgentConnection extends AbstractStrategyEngineConnection {
private static final String NAME_KEY = "Name"; //$NON-NLS-1$
private static final String LANGUAGE_KEY = "Language"; //$NON-NLS-1$
private static final String PARAMETERS_KEY = "Parameters"; //$NON-NLS-1$
private static final String ROUTING_ORDERS_TO_ORS_KEY = "RoutingOrdersToORS"; //$NON-NLS-1$
private static final ModuleURN STRATEGY_PROVIDER_URN = new ModuleURN(
"metc:strategy:system"); //$NON-NLS-1$
private final SAClient mClient;
/**
* Constructor.
*
* @param client
* the client
* @param guiExecutor
* the gui executor
* @throws IllegalArgumentException
* if client or guiExecutor is null
*/
public StrategyAgentConnection(SAClient client, ExecutorService guiExecutor) {
super(guiExecutor);
Validate.notNull(client, "client"); //$NON-NLS-1$
mClient = client;
}
@Override
protected ModuleURN doDeploy(Strategy strategy, File script)
throws Exception {
CreateStrategyParameters parameters = new CreateStrategyParameters(
strategy.getInstanceName(), strategy.getClassName(), strategy
.getLanguage(), script, getPropertiesString(strategy),
strategy.isRouteOrdersToServer());
return mClient.createStrategy(parameters);
}
@Override
protected void doUpdate(ModuleURN urn, Strategy newConfiguration)
throws Exception {
// can't use ImmutableMap.of because properties may be null
Map<String, Object> map = Maps.newHashMap();
map.put(ROUTING_ORDERS_TO_ORS_KEY, newConfiguration
.isRouteOrdersToServer());
String properties = getPropertiesString(newConfiguration);
map.put(PARAMETERS_KEY, properties);
Map<String, Object> result = mClient.setProperties(urn, map);
StringBuilder errorMessage = new StringBuilder(); //$NON-NLS-1$
boolean errorFound = appendError(result.get(ROUTING_ORDERS_TO_ORS_KEY),
newConfiguration.isRouteOrdersToServer(), errorMessage,
Messages.STRATEGY_AGENT_CONNECTION_UPDATE_ROUTING_ERROR, false);
errorFound |= appendError(result.get(PARAMETERS_KEY), properties,
errorMessage,
Messages.STRATEGY_AGENT_CONNECTION_UPDATE_PARAMETERS_ERROR,
errorFound);
if (errorFound) {
throw new Exception(errorMessage.toString());
}
}
/* (non-Javadoc)
* @see org.marketcetera.photon.strategy.engine.model.core.impl.StrategyEngineConnectionImpl#sendData(java.lang.Object)
*/
@Override
public void sendData(Object inData)
throws Exception
{
mClient.sendData(inData);
}
private boolean appendError(Object result, Object value,
StringBuilder errorMessage, I18NMessage2P description,
boolean errorFound) {
if (result instanceof RemoteProperties) {
if (errorFound) {
errorMessage.append('\n');
}
errorMessage.append(description.getText(value,
((RemoteProperties) result).getServerMessage()));
return true;
}
return false;
}
@Override
protected void doRefresh(ModuleURN urn, DeployedStrategy strategy)
throws ConnectionException {
/*
* Pull all properties, even immutable ones like language and name since
* we may be refreshing strategies deployed by other means.
*/
Map<String, Object> properties = mClient.getProperties(urn);
strategy.setLanguage((String) properties.get(LANGUAGE_KEY));
strategy.setClassName((String) properties.get(NAME_KEY));
strategy.setInstanceName(urn.instanceName());
strategy.setRouteOrdersToServer((Boolean) properties
.get(ROUTING_ORDERS_TO_ORS_KEY));
strategy.getParameters().clear();
strategy.getParameters().putAll(
getPropertiesMap((String) properties.get(PARAMETERS_KEY)));
}
@Override
protected boolean isRunning(ModuleURN urn) throws ConnectionException {
return mClient.getModuleInfo(urn).getState().isStarted();
}
@Override
protected void doStart(ModuleURN urn) throws ConnectionException {
mClient.start(urn);
}
@Override
protected void doStop(ModuleURN urn) throws ConnectionException {
mClient.stop(urn);
}
@Override
protected void doUndeploy(ModuleURN urn) throws ConnectionException {
mClient.delete(urn);
}
@Override
protected List<ModuleURN> getDeployed() throws ConnectionException {
return mClient.getInstances(STRATEGY_PROVIDER_URN);
}
}