/* * Copyright (c) 2004-2011 Marco Maccaferri and others. * 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: * Marco Maccaferri - initial API and implementation */ package org.eclipsetrader.core.internal.ats; import java.io.File; import java.io.FileWriter; import java.util.ArrayList; import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.ValidationEvent; import javax.xml.bind.ValidationEventHandler; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipsetrader.core.ats.IStrategy; import org.eclipsetrader.core.ats.ITradingSystem; import org.eclipsetrader.core.ats.ITradingSystemListener; import org.eclipsetrader.core.ats.ITradingSystemService; import org.eclipsetrader.core.ats.TradingSystemEvent; import org.eclipsetrader.core.internal.CoreActivator; import org.eclipsetrader.core.internal.ats.repository.SettingsCollection; import org.eclipsetrader.core.markets.IMarketService; import org.eclipsetrader.core.repositories.IRepositoryChangeListener; import org.eclipsetrader.core.repositories.IRepositoryService; import org.eclipsetrader.core.repositories.IStoreObject; import org.eclipsetrader.core.repositories.RepositoryChangeEvent; import org.eclipsetrader.core.repositories.RepositoryResourceDelta; public class TradingSystemService implements ITradingSystemService { private final IRepositoryService repositoryService; private final IMarketService marketService; private final List<TradingSystem> list = new ArrayList<TradingSystem>(); private SettingsCollection collection; private final ListenerList listeners = new ListenerList(ListenerList.IDENTITY); private final IRepositoryChangeListener repositoryChangeListener = new IRepositoryChangeListener() { @Override public void repositoryResourceChanged(RepositoryChangeEvent event) { RepositoryResourceDelta[] delta = event.getDeltas(); for (int i = 0; i < delta.length; i++) { if (delta[i].getResource() instanceof IStrategy) { IStrategy strategy = (IStrategy) delta[i].getResource(); if ((delta[i].getKind() & RepositoryResourceDelta.ADDED) != 0) { TradingSystem tradingSystem = new TradingSystem(strategy); TradingSystemProperties properties = collection.getSettingsFor(strategy); if (properties != null) { tradingSystem.setProperties(properties); } list.add(tradingSystem); fireTradingSystemEvent(new TradingSystemEvent(TradingSystemEvent.KIND_ADDED, tradingSystem)); } else if ((delta[i].getKind() & RepositoryResourceDelta.REMOVED) != 0) { for (TradingSystem tradingSystem : list) { if (tradingSystem.getStrategy() == strategy) { tradingSystem.stop(); list.remove(tradingSystem); fireTradingSystemEvent(new TradingSystemEvent(TradingSystemEvent.KIND_REMOVED, tradingSystem)); break; } } } } } } }; public TradingSystemService(IRepositoryService repositoryService, IMarketService marketService) { this.repositoryService = repositoryService; this.marketService = marketService; } public void startUp() { for (IStoreObject object : repositoryService.getAllObjects()) { if (object instanceof IStrategy) { list.add(new TradingSystem((IStrategy) object)); } } loadSettings(CoreActivator.getDefault().getStateLocation().append("trade_systems.xml").toFile()); repositoryService.addRepositoryResourceListener(repositoryChangeListener); } public void shutDown() { repositoryService.removeRepositoryResourceListener(repositoryChangeListener); for (TradingSystem system : list) { try { system.stop(); } catch (Throwable t) { Status status = new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, "Error stopping trading system", t); CoreActivator.log(status); } } saveSettings(CoreActivator.getDefault().getStateLocation().append("trade_systems.xml").toFile()); } /* (non-Javadoc) * @see org.eclipsetrader.core.ats.ITradingSystemService#getTradeSystems() */ @Override public ITradingSystem[] getTradeSystems() { return list.toArray(new ITradingSystem[list.size()]); } /* (non-Javadoc) * @see org.eclipsetrader.core.ats.ITradingSystemService#start() */ @Override public void start() { for (TradingSystem system : list) { TradingSystemProperties properties = system.getProperties(); if (properties.isAutostart()) { start(system); } } } /* (non-Javadoc) * @see org.eclipsetrader.core.ats.ITradingSystemService#stop() */ @Override public void stop() { for (TradingSystem system : list) { stop(system); } } /* (non-Javadoc) * @see org.eclipsetrader.core.ats.ITradingSystemService#start(org.eclipsetrader.core.ats.ITradeSystem) */ @Override public void start(final ITradingSystem system) { ((TradingSystem) system).setStatus(ITradingSystem.STATUS_STARTING); Job job = new Job("Starting " + system.getStrategy().getName()) { @Override protected IStatus run(IProgressMonitor monitor) { TradingSystemProperties properties = ((TradingSystem) system).getProperties(); TradingSystemContext context = new TradingSystemContext(marketService, system.getStrategy(), properties.getBroker(), properties.getAccount()); context.setInitialBackfillSize(properties.getBackfill()); try { system.start(context); ((TradingSystem) system).setStatus(ITradingSystem.STATUS_STARTED); } catch (Exception e) { ((TradingSystem) system).setStatus(ITradingSystem.STATUS_STOPPED); return new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, "Error starting trade system", e); } return Status.OK_STATUS; } }; job.setUser(false); job.schedule(); } /* (non-Javadoc) * @see org.eclipsetrader.core.ats.ITradingSystemService#stop(org.eclipsetrader.core.ats.ITradeSystem) */ @Override public void stop(final ITradingSystem system) { ((TradingSystem) system).setStatus(ITradingSystem.STATUS_STOPPING); Job job = new Job("Stopping " + system.getStrategy().getName()) { @Override protected IStatus run(IProgressMonitor monitor) { try { system.stop(); } catch (Exception e) { return new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, "Error starting trade system", e); } finally { ((TradingSystem) system).setStatus(ITradingSystem.STATUS_STOPPED); } return Status.OK_STATUS; } }; job.setUser(false); job.schedule(); } /* (non-Javadoc) * @see org.eclipsetrader.core.ats.ITradingSystemService#addTradingSystemListener(org.eclipsetrader.core.ats.ITradingSystemListener) */ @Override public void addTradingSystemListener(ITradingSystemListener listener) { listeners.add(listener); } /* (non-Javadoc) * @see org.eclipsetrader.core.ats.ITradingSystemService#removeTradingSystemListener(org.eclipsetrader.core.ats.ITradingSystemListener) */ @Override public void removeTradingSystemListener(ITradingSystemListener listener) { listeners.remove(listener); } protected void fireTradingSystemEvent(TradingSystemEvent event) { Object[] l = listeners.getListeners(); for (int i = 0; i < l.length; i++) { try { ((ITradingSystemListener) l[i]).tradingSystemChanged(event); } catch (Throwable t) { Status status = new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, 0, "Error notifying listeners", t); //$NON-NLS-1$ CoreActivator.log(status); } } } private void loadSettings(File file) { if (file.exists() == true) { try { JAXBContext jaxbContext = JAXBContext.newInstance(SettingsCollection.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); unmarshaller.setEventHandler(new ValidationEventHandler() { @Override public boolean handleEvent(ValidationEvent event) { Status status = new Status(IStatus.WARNING, CoreActivator.PLUGIN_ID, 0, "Error validating XML: " + event.getMessage(), null); //$NON-NLS-1$ CoreActivator.log(status); return true; } }); collection = (SettingsCollection) unmarshaller.unmarshal(file); } catch (Exception e) { Status status = new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, 0, "Error loading repository", e); //$NON-NLS-1$ CoreActivator.log(status); } } if (collection == null) { collection = new SettingsCollection(); } for (TradingSystem system : list) { TradingSystemProperties properties = collection.getSettingsFor(system.getStrategy()); if (properties != null) { system.setProperties(properties); } } } private void saveSettings(File file) { try { if (file.exists()) { file.delete(); } for (TradingSystem system : list) { collection.setSettingsFor(system.getStrategy(), system.getProperties()); } JAXBContext jaxbContext = JAXBContext.newInstance(SettingsCollection.class); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); marshaller.setProperty(Marshaller.JAXB_ENCODING, System.getProperty("file.encoding")); //$NON-NLS-1$ marshaller.setEventHandler(new ValidationEventHandler() { @Override public boolean handleEvent(ValidationEvent event) { Status status = new Status(IStatus.WARNING, CoreActivator.PLUGIN_ID, 0, "Error validating XML: " + event.getMessage(), null); //$NON-NLS-1$ CoreActivator.log(status); return true; } }); marshaller.marshal(collection, new FileWriter(file)); } catch (Exception e) { Status status = new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, 0, "Error saving repository", e); //$NON-NLS-1$ CoreActivator.log(status); } } }