package org.marketcetera.strategyagent; import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.management.Attribute; import javax.management.AttributeList; import javax.management.InstanceNotFoundException; import javax.management.IntrospectionException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.ReflectionException; import org.marketcetera.core.Util; import org.marketcetera.core.publisher.IPublisher; import org.marketcetera.module.ModuleInfo; import org.marketcetera.module.ModuleManager; import org.marketcetera.module.ModuleURN; import org.marketcetera.modules.remote.receiver.ReceiverFactory; import org.marketcetera.saclient.CreateStrategyParameters; import org.marketcetera.saclient.SAService; import org.marketcetera.saclient.rpc.SAServiceAdapter; import org.marketcetera.util.except.I18NException; import org.marketcetera.util.file.CopyBytesUtils; import org.marketcetera.util.log.I18NBoundMessage1P; import org.marketcetera.util.log.I18NBoundMessage3P; import org.marketcetera.util.log.I18NMessage1P; import org.marketcetera.util.misc.ClassVersion; import org.marketcetera.util.ws.stateful.ClientContext; import org.marketcetera.util.ws.stateful.RemoteCaller; import org.marketcetera.util.ws.stateful.ServiceBaseImpl; import org.marketcetera.util.ws.stateful.SessionHolder; import org.marketcetera.util.ws.stateful.SessionManager; import org.marketcetera.util.ws.wrappers.MapWrapper; import org.marketcetera.util.ws.wrappers.RemoteException; import org.marketcetera.util.ws.wrappers.RemoteProperties; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /* $License$ */ /** * Implements the remote web services offered by the strategy agent. * * @author anshul@marketcetera.com * @version $Id: SAServiceImpl.java 16879 2014-04-15 21:40:25Z colin $ * @since 2.0.0 */ @ClassVersion("$Id: SAServiceImpl.java 16879 2014-04-15 21:40:25Z colin $") public class SAServiceImpl extends ServiceBaseImpl<ClientSession> implements SAService,SAServiceAdapter { @Override public List<ModuleURN> getProviders(ClientContext inCtx) throws RemoteException { return new RemoteCaller<ClientSession,List<ModuleURN>>(getSessionManager()) { @Override protected List<ModuleURN> call(ClientContext context, SessionHolder<ClientSession> sessionHolder) throws Exception { return doGetProviders(); } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#getProviders() */ @Override public List<ModuleURN> getProviders() { return doGetProviders(); } @Override public List<ModuleURN> getInstances(ClientContext inCtx, final ModuleURN inProviderURN) throws RemoteException { return new RemoteCaller<ClientSession,List<ModuleURN>>(getSessionManager()) { @Override protected List<ModuleURN> call(ClientContext inContext, SessionHolder<ClientSession> inSessionHolder) throws Exception { return doGetInstances(inProviderURN); } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#getInstances(org.marketcetera.module.ModuleURN) */ @Override public List<ModuleURN> getInstances(ModuleURN inProvider) { return doGetInstances(inProvider); } @Override public ModuleInfo getModuleInfo(ClientContext inCtx, final ModuleURN inURN) throws RemoteException { return new RemoteCaller<ClientSession,ModuleInfo>(getSessionManager()) { @Override protected ModuleInfo call(ClientContext context, SessionHolder<ClientSession> sessionHolder) throws Exception { return doGetModuleInfo(inURN); } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#getModuleInfo(org.marketcetera.module.ModuleURN) */ @Override public ModuleInfo getModuleInfo(ModuleURN inInstance) { return doGetModuleInfo(inInstance); } @Override public void start(ClientContext inCtx, final ModuleURN inURN) throws RemoteException { new RemoteCaller<ClientSession,Void>(getSessionManager()) { @Override protected Void call(ClientContext inContext, SessionHolder<ClientSession> inSessionHolder) throws Exception { doStart(inURN); return null; } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#start(org.marketcetera.module.ModuleURN) */ @Override public void start(ModuleURN inInstance) { doStart(inInstance); } @Override public void stop(ClientContext inCtx, final ModuleURN inURN) throws RemoteException { new RemoteCaller<ClientSession,Void>(getSessionManager()) { @Override protected Void call(ClientContext context, SessionHolder<ClientSession> sessionHolder) throws Exception { doStop(inURN); return null; } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#stop(org.marketcetera.module.ModuleURN) */ @Override public void stop(ModuleURN inInstance) { doStop(inInstance); } /* (non-Javadoc) * @see org.marketcetera.saclient.SAService#sendData(org.marketcetera.util.ws.stateful.ClientContext, java.lang.Object) */ @Override public void sendData(ClientContext inServiceContext, final Object inData) throws RemoteException { new RemoteCaller<ClientSession,Void>(getSessionManager()) { @Override protected Void call(ClientContext inContext, SessionHolder<ClientSession> inSessionHolder) throws Exception { doSendData(inData); return null; } }.execute(inServiceContext); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#sendData(java.lang.Object) */ @Override public void sendData(Object inData) { doSendData(inData); } @Override public void delete(ClientContext inCtx, final ModuleURN inURN) throws RemoteException { new RemoteCaller<ClientSession, Void>(getSessionManager()){ @Override protected Void call(ClientContext context, SessionHolder<ClientSession> sessionHolder) throws Exception { failOnNullURN(inURN); failIfNotStrategy(inURN, Messages.DELETE_MODULE_NOT_STRATEGY); mManager.deleteModule(inURN); //Remove the strategy create parameter value. mStrategies.remove(inURN); return null; } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#delete(org.marketcetera.module.ModuleURN) */ @Override public void delete(ModuleURN inInstance) { failOnNullURN(inInstance); failIfNotStrategy(inInstance, Messages.DELETE_MODULE_NOT_STRATEGY); mManager.deleteModule(inInstance); //Remove the strategy create parameter value. mStrategies.remove(inInstance); } @Override public MapWrapper<String,Object> getProperties(ClientContext inCtx, final ModuleURN inURN) throws RemoteException { return new RemoteCaller<ClientSession,MapWrapper<String,Object>>(getSessionManager()) { @Override protected MapWrapper<String,Object> call(ClientContext inContext, SessionHolder<ClientSession> inSessionHolder) throws Exception { return new MapWrapper<String,Object>(doGetProperties(inURN)); } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#getProperties(org.marketcetera.module.ModuleURN) */ @Override public Map<String,Object> getProperties(ModuleURN inInstance) { try { return doGetProperties(inInstance); } catch (IntrospectionException | InstanceNotFoundException | ReflectionException e) { throw new RuntimeException(e); } } @Override public MapWrapper<String,Object> setProperties(ClientContext inCtx, final ModuleURN inURN, final MapWrapper<String,Object> inProperties) throws RemoteException { return new RemoteCaller<ClientSession,MapWrapper<String,Object>>(getSessionManager()) { @Override protected MapWrapper<String,Object> call(ClientContext inContext, SessionHolder<ClientSession> inSessionHolder) throws Exception { return new MapWrapper<String,Object>(doSetProperties(inURN, inProperties.getMap())); } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#setProperties(org.marketcetera.module.ModuleURN, java.util.Map) */ @Override public Map<String,Object> setProperties(ModuleURN inInstance, Map<String,Object> inProperties) { try { return doSetProperties(inInstance, inProperties); } catch (InstanceNotFoundException | ReflectionException e) { throw new RuntimeException(e); } } @Override public ModuleURN createStrategy(ClientContext inCtx, final CreateStrategyParameters inParameters) throws RemoteException { return new RemoteCaller<ClientSession,ModuleURN>(getSessionManager()) { @Override protected ModuleURN call(ClientContext inContext, SessionHolder<ClientSession> inSessionHolder) throws Exception { return doCreateStrategy(inParameters); } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#createStrategy(org.marketcetera.saclient.CreateStrategyParameters) */ @Override public ModuleURN createStrategy(CreateStrategyParameters inParameters) { try { return doCreateStrategy(inParameters); } catch (IOException e) { throw new RuntimeException(e); } } @Override public CreateStrategyParameters getStrategyCreateParms(ClientContext inCtx, final ModuleURN inURN) throws RemoteException { return new RemoteCaller<ClientSession,CreateStrategyParameters>(getSessionManager()) { @Override protected CreateStrategyParameters call(ClientContext inContext, SessionHolder<ClientSession> inSessionHolder) throws Exception { return doGetStrategyCreateParms(inURN); } }.execute(inCtx); } /* (non-Javadoc) * @see org.marketcetera.saclient.rpc.SAServiceAdapter#getStrategyCreateParms(org.marketcetera.module.ModuleURN) */ @Override public CreateStrategyParameters getStrategyCreateParms(ModuleURN inInstance) { return doGetStrategyCreateParms(inInstance); } /** * Creates an instance. * * @param inSessionManager the session manager. * @param inManager the module manager. * @param inPublisher an <code>IPublisher</code> value */ public SAServiceImpl(SessionManager<ClientSession> inSessionManager, ModuleManager inManager, IPublisher inPublisher) { super(inSessionManager); mManager = inManager; dataPublisher = inPublisher; } /** * Throws an exception if the supplied URN is null. * * @param inURN the URN to test. * * @throws I18NException if the supplied URN is null. */ private static void failOnNullURN(ModuleURN inURN) throws I18NException { if(inURN == null) { throw new I18NException(Messages.CANNOT_PROCESS_NULL_URN); } } /** * Throws an exception with the supplied message if the supplied URN * is not a strategy module URN. * * @param inURN the URN to test. * @param inFailureMessage the message to use in the exception. * * @throws I18NException if the supplied URN is not a strategy URN. */ private static void failIfNotStrategy(ModuleURN inURN, I18NMessage1P inFailureMessage) throws I18NException { if(!STRATEGY_PROVIDER.parentOf(inURN)) { throw new I18NException(new I18NBoundMessage1P( inFailureMessage, inURN)); } } /** * Returns the MBean server to use for all MBean operations. * * @return the MBean server instance. */ private static MBeanServer getMBeanServer() { return ManagementFactory.getPlatformMBeanServer(); } /** * Gets module info for the given URN. * * @param inInstance a <code>ModuleURN</code> value * @return a <code>ModuleInfo</code> value */ private ModuleInfo doGetModuleInfo(ModuleURN inInstance) { failOnNullURN(inInstance); return mManager.getModuleInfo(inInstance); } /** * Gets the list of providers. * * @return a <code>List<ModuleURN</code> value */ private List<ModuleURN> doGetProviders() { return mManager.getProviders(); } /** * Gets the instances for the given provider URN. * * @param inProvider a <code>ModuleURN</code> value * @return a <code>List<ModuleURN</code> value */ private List<ModuleURN> doGetInstances(ModuleURN inProvider) { return mManager.getModuleInstances(inProvider); } /** * Stops the module with the given URN. * * @param inInstance a <code>ModuleURN</code> value */ private void doStop(ModuleURN inInstance) { failOnNullURN(inInstance); failIfNotStrategy(inInstance, Messages.STOP_MODULE_NOT_STRATEGY); mManager.stop(inInstance); } /** * Sends the given data. * * @param inData an <code>Object</code> value */ private void doSendData(Object inData) { dataPublisher.publish(inData); } /** * Starts the module with the given URN. * * @param inInstance a <code>ModuleURN</code> value */ private void doStart(ModuleURN inInstance) { failOnNullURN(inInstance); failIfNotStrategy(inInstance, Messages.START_MODULE_NOT_STRATEGY); mManager.start(inInstance); } /** * Gets the properties for the given module. * * @param inInstance a <code>ModuleURN</code> value * @return a <code>Map<String,Object></code> value * @throws IntrospectionException if an error occurs transcribing the properties * @throws InstanceNotFoundException if an error occurs transcribing the properties * @throws ReflectionException if an error occurs transcribing the properties */ private Map<String,Object> doGetProperties(ModuleURN inInstance) throws IntrospectionException, InstanceNotFoundException, ReflectionException { failOnNullURN(inInstance); ObjectName on = inInstance.toObjectName(); MBeanServer beanServer = getMBeanServer(); List<String> attribs = Lists.newArrayList(); for(MBeanAttributeInfo info: beanServer.getMBeanInfo(on).getAttributes()) { attribs.add(info.getName()); } AttributeList values = beanServer.getAttributes(on, attribs.toArray(new String[attribs.size()])); Map<String,Object> props = Maps.newHashMap(); for(Attribute a: values.asList()) { props.put(a.getName(), a.getValue()); } return props; } /** * Sets the properties for the given module. * * @param inInstance a <code>ModuleURN</code> value * @param inProperties a <code>Map<String,Object></code> value * @return a <code>Map<String,Object></code> value * @throws InstanceNotFoundException if an error occurs transcribing the properties * @throws ReflectionException if an error occurs transcribing the properties */ private Map<String,Object> doSetProperties(ModuleURN inInstance, Map<String,Object> inProperties) throws InstanceNotFoundException, ReflectionException { failOnNullURN(inInstance); failIfNotStrategy(inInstance, Messages.SET_PROPERTY_MODULE_NOT_STRATEGY); AttributeList list = new AttributeList(); Map<String,Object> output = Maps.newHashMap(); if (inProperties != null) { for(String key: inProperties.keySet()) { if(!EDITABLE_STRATEGY_PROPERTIES.contains(key)) { throw new I18NException(new I18NBoundMessage3P(Messages.UNEDITABLE_STRATEGY_PROPERTY, key, inInstance, EDITABLE_STRATEGY_PROPERTIES.toString())); } } ObjectName on = inInstance.toObjectName(); MBeanServer beanServer = getMBeanServer(); beanServer.setAttributes(on, list); for(String key: inProperties.keySet()) { try { Object value = inProperties.get(key); beanServer.setAttribute(on, new Attribute(key, value)); output.put(key, value); } catch (Exception e) { output.put(key, new RemoteProperties(e)); Messages.LOG_ERROR_SET_ATTRIBUTE.error(this, e, key, inInstance); } } } return output; } /** * Creates a strategy with the given parameters. * * @param inParameters a <code>CreateStrategyParameters</code> value * @return a <code>ModuleURN</code> value * @throws IOException if an error occurs creating the strategy */ private ModuleURN doCreateStrategy(CreateStrategyParameters inParameters) throws IOException { if(inParameters == null) { throw new I18NException(Messages.NO_STRATEGY_CREATE_PARMS_SPECIFIED); } // copy the input stream to file. File file = File.createTempFile("strat", //$NON-NLS-1$ ".tmp"); //$NON-NLS-1$ file.deleteOnExit(); CopyBytesUtils.copy(inParameters.getStrategySource(), false, file.getAbsolutePath()); // Generate the strategy creation parameter referencing the local copy CreateStrategyParameters sp = new CreateStrategyParameters(inParameters.getInstanceName(), inParameters.getStrategyName(), inParameters.getLanguage(), file, inParameters.getParameters(), inParameters.isRouteOrdersToServer()); ModuleURN urn = null; try { urn = mManager.createModule(STRATEGY_PROVIDER, inParameters.getInstanceName(), inParameters.getStrategyName(), inParameters.getLanguage(), file, Util.propertiesFromString(inParameters.getParameters()), inParameters.isRouteOrdersToServer(), REMOTE_RECEIVER); return urn; } finally { if(urn != null) { mStrategies.put(urn, sp); } } } /** * Gets the strategy parameters for the given module. * * @param inInstance a <code>ModuleURN</code> value * @return a <code>CreateStrategyParameters</code> value */ private CreateStrategyParameters doGetStrategyCreateParms(ModuleURN inInstance) { failOnNullURN(inInstance); CreateStrategyParameters parameters = mStrategies.get(inInstance); if(parameters == null) { throw new I18NException(new I18NBoundMessage1P(Messages.NO_CREATE_PARAMETERS_FOR_STRATEGY, inInstance)); } return parameters; } /** * publisher responsible for distributing data to interested publishers */ private final IPublisher dataPublisher; private final ModuleManager mManager; private final Map<ModuleURN,CreateStrategyParameters> mStrategies = Maps.newConcurrentMap(); private static final ModuleURN REMOTE_RECEIVER = ReceiverFactory.PROVIDER_URN; private static final ModuleURN STRATEGY_PROVIDER = new ModuleURN("metc:strategy:system"); //$NON-NLS-1$ static final Set<String> EDITABLE_STRATEGY_PROPERTIES = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList( "Parameters", //$NON-NLS-1$ "RoutingOrdersToORS" //$NON-NLS-1$ ))); }