/******************************************************************************* * Copyright (c) 2013 Luigi Sgro. 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: * Luigi Sgro - initial API and implementation ******************************************************************************/ package com.quantcomponents.algo.container.serializing; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.concurrent.CopyOnWriteArrayList; import java.util.logging.Level; import java.util.logging.Logger; import com.quantcomponents.algo.DummyTradingAgentExecution; import com.quantcomponents.algo.IHierarchyItemHandle; import com.quantcomponents.algo.ITradingAgentExecution; import com.quantcomponents.algo.ITradingAgentFactory; import com.quantcomponents.algo.MemoryTradingAgentHierarchyContainer; import com.quantcomponents.algo.TradingAgentBinding; import com.quantcomponents.algo.TradingAgentBindingHandle; import com.quantcomponents.algo.TradingAgentConfiguration; import com.quantcomponents.algo.TradingAgentConfigurationHandle; import com.quantcomponents.algo.TradingAgentExecutionHandle; import com.quantcomponents.algo.TradingAgentFactoryHandle; import com.quantcomponents.core.model.ISeries; import com.quantcomponents.core.model.ISeriesAugmentable; import com.quantcomponents.core.model.ISeriesPoint; import com.quantcomponents.marketdata.IMarketDataManager; public class SerializingTradingAgentHierarchyContainer extends MemoryTradingAgentHierarchyContainer { private static class BindingPersistentData implements Serializable { private static final long serialVersionUID = -3389176585646320417L; Map<String, String> inputSeriesNames = new HashMap<String, String>(); IHierarchyItemHandle configurationHandle; } private static class ExecutionPersistentData implements Serializable { private static final long serialVersionUID = 6022916144134872069L; Map<String, String> inputSeriesNames = new HashMap<String, String>(); ISeries<Date, Double, ISeriesPoint<Date, Double>> outputSeries; } private static final Logger logger = Logger.getLogger(SerializingTradingAgentHierarchyContainer.class.getName()); public static final String DEFAULT_PERSISTENCE_DIR_NAME = "."; public static final String PERSISTENCE_DIR_NAME_KEY = "persistence.directory"; private volatile IMarketDataManager marketDataManager; private volatile File persistenceDirectory; public void setMarketDataManager(IMarketDataManager marketDataManager) { this.marketDataManager = marketDataManager; } public void activate(Map<?,?> properties) { String persistenceDirName = (String) properties.get(PERSISTENCE_DIR_NAME_KEY); if (persistenceDirName == null) { persistenceDirName = DEFAULT_PERSISTENCE_DIR_NAME; } persistenceDirectory = new File(persistenceDirName); } public void deactivate() { saveState(); } @Override public void addTradingAgentFactory(ITradingAgentFactory factory) { super.addTradingAgentFactory(factory); TradingAgentFactoryHandle factoryHandle = new TradingAgentFactoryHandle(factory.getClass().getName(), factory.getConfigurationKeys()); if (persistenceDirectory.exists() && persistenceDirectory.isDirectory()) { File[] dirFiles = persistenceDirectory.listFiles(); String dataFileName = factoryHandle.getPrettyName() + ".hierarchy"; for (File file : dirFiles) { if (file.getName().equals(dataFileName)) { try { FileInputStream inputStream = new FileInputStream(file); restoreFactoryHierarchy(factoryHandle, inputStream); inputStream.close(); } catch (Exception e) { logger.log(Level.SEVERE, "Error while restoring hierarchy data from file: '" + file.getAbsolutePath() + "'", e); } break; } } } } @Override public void removeTradingAgentFactory(ITradingAgentFactory factory) { TradingAgentFactoryHandle factoryHandle = new TradingAgentFactoryHandle(factory.getClass().getName(), factory.getConfigurationKeys()); persistFactoryHierarchy(factoryHandle); super.removeTradingAgentFactory(factory); } public void saveState() { for (TradingAgentFactoryHandle factoryHandle : factoriesByHandle.keySet()) { persistFactoryHierarchy(factoryHandle); } } private synchronized void persistFactoryHierarchy(TradingAgentFactoryHandle factoryHandle) { if (persistenceDirectory.exists()) { String fileName = persistenceDirectory.getAbsolutePath() + File.separator + factoryHandle.getPrettyName() + ".hierarchy"; try { FileOutputStream outputStream = new FileOutputStream(fileName); persistFactoryHierarchy(factoryHandle, outputStream); outputStream.close(); } catch (Exception e) { logger.log(Level.SEVERE, "Error while persisting hierarchy data to file: '" + fileName + "'", e); } } } private void persistFactoryHierarchy(TradingAgentFactoryHandle factoryHandle, OutputStream outputStream) throws IOException { Map<IHierarchyItemHandle, HierarchyItem> factoryHierarchy = new HashMap<IHierarchyItemHandle, HierarchyItem>(); Map<TradingAgentConfigurationHandle, Properties> factoryConfigurationByHandle = new HashMap<TradingAgentConfigurationHandle, Properties>(); Map<TradingAgentBindingHandle, BindingPersistentData> factoryBindingByHandle = new HashMap<TradingAgentBindingHandle, BindingPersistentData>(); Map<TradingAgentExecutionHandle, ExecutionPersistentData> factoryExecutionByHandle = new HashMap<TradingAgentExecutionHandle, ExecutionPersistentData>(); HierarchyItem factoryHierarchyItem = hierarchy.get(factoryHandle); for (IHierarchyItemHandle configurationHandle : factoryHierarchyItem.children) { HierarchyItem configurationInfo = hierarchy.get(configurationHandle); factoryHierarchy.put(configurationHandle, configurationInfo); factoryConfigurationByHandle.put((TradingAgentConfigurationHandle) configurationHandle, configurationByHandle.get(configurationHandle).getProperties()); for (IHierarchyItemHandle bindingHandle : configurationInfo.children) { HierarchyItem bindingInfo = hierarchy.get(bindingHandle); factoryHierarchy.put(bindingHandle, bindingInfo); TradingAgentBinding binding = bindingByHandle.get(bindingHandle); BindingPersistentData bindingData = new BindingPersistentData(); bindingData.configurationHandle = configurationHandle; bindingData.inputSeriesNames = encodeInputSeriesMap(binding.getInputSeries()); factoryBindingByHandle.put((TradingAgentBindingHandle) bindingHandle, bindingData); for (IHierarchyItemHandle executionHandle : bindingInfo.children) { HierarchyItem executionInfo = hierarchy.get(executionHandle); factoryHierarchy.put(executionHandle, executionInfo); ITradingAgentExecution execution = executionByHandle.get(executionHandle); ExecutionPersistentData executionData = new ExecutionPersistentData(); executionData.inputSeriesNames = encodeInputSeriesMap(execution.getInput()); executionData.outputSeries = execution.getOutput(); factoryExecutionByHandle.put((TradingAgentExecutionHandle) executionHandle, executionData); } } } ObjectOutputStream oos = new ObjectOutputStream(outputStream); oos.writeObject(factoryConfigurationByHandle); oos.writeObject(factoryBindingByHandle); oos.writeObject(factoryExecutionByHandle); oos.writeObject(factoryHierarchy); oos.close(); } @SuppressWarnings("unchecked") private void restoreFactoryHierarchy(TradingAgentFactoryHandle factoryHandle, InputStream inputStream) throws IOException, ClassNotFoundException { Map<IHierarchyItemHandle, IHierarchyItemHandle> handleIdentities = new HashMap<IHierarchyItemHandle, IHierarchyItemHandle>(); ObjectInputStream ois = new ObjectInputStream(inputStream); Map<TradingAgentConfigurationHandle, Properties> factoryConfigurationByHandle = (Map<TradingAgentConfigurationHandle, Properties>) ois.readObject(); Map<TradingAgentBindingHandle, BindingPersistentData> factoryBindingByHandle = (Map<TradingAgentBindingHandle, BindingPersistentData>) ois.readObject(); Map<TradingAgentExecutionHandle, ExecutionPersistentData> factoryExecutionByHandle = (Map<TradingAgentExecutionHandle, ExecutionPersistentData>) ois.readObject(); Map<IHierarchyItemHandle, HierarchyItem> factoryHierarchy = (Map<IHierarchyItemHandle, HierarchyItem>) ois.readObject(); HierarchyItem factoryHierarchyItem = hierarchy.get(factoryHandle); handleIdentities.put(factoryHandle, factoryHandle); ITradingAgentFactory factory = factoriesByHandle.get(factoryHandle); for (Map.Entry<TradingAgentConfigurationHandle, Properties> entry : factoryConfigurationByHandle.entrySet()) { configurationByHandle.put(entry.getKey(), new TradingAgentConfiguration(factory, entry.getValue())); factoryHierarchyItem.children.add(entry.getKey()); handleIdentities.put(entry.getKey(), entry.getKey()); } for (Map.Entry<TradingAgentBindingHandle, BindingPersistentData> entry : factoryBindingByHandle.entrySet()) { TradingAgentConfiguration configuration = configurationByHandle.get(entry.getValue().configurationHandle); TradingAgentBinding binding = new TradingAgentBinding(configuration, decodeInputSeriesMap(entry.getValue().inputSeriesNames)); bindingByHandle.put(entry.getKey(), binding); handleIdentities.put(entry.getKey(), entry.getKey()); } for (Map.Entry<TradingAgentExecutionHandle, ExecutionPersistentData> entry : factoryExecutionByHandle.entrySet()) { DummyTradingAgentExecution execution = new DummyTradingAgentExecution(); execution.wire(decodeInputSeriesMap(entry.getValue().inputSeriesNames), (ISeriesAugmentable<Date, Double, ISeriesPoint<Date, Double>>) entry.getValue().outputSeries); executionByHandle.put(entry.getKey(), execution); handleIdentities.put(entry.getKey(), entry.getKey()); } for (Map.Entry<IHierarchyItemHandle, HierarchyItem> entry : factoryHierarchy.entrySet()) { IHierarchyItemHandle key = handleIdentities.get(entry.getKey()); HierarchyItem item = entry.getValue(); item.parent = handleIdentities.get(item.parent); // substitute 'copy' handle with 'real' handle CopyOnWriteArrayList<IHierarchyItemHandle> children = new CopyOnWriteArrayList<IHierarchyItemHandle>(); for (IHierarchyItemHandle child : item.children) { children.add(handleIdentities.get(child)); // add 'real' handle instead of 'copy' handle } item.children = children; hierarchy.put(key, item); } } private Map<String, String> encodeInputSeriesMap(Map<String, ? extends ISeries<Date, Double, ? extends ISeriesPoint<Date, Double>>> inputSeriesMap) { Map<String, String> inputMap = new HashMap<String, String>(); for (Map.Entry<String, ? extends ISeries<Date, Double, ? extends ISeriesPoint<Date, Double>>> seriesEntry : inputSeriesMap.entrySet()) { inputMap.put(seriesEntry.getKey(), seriesEntry.getValue().getPersistentID()); } return inputMap; } private Map<String, ISeries<Date, Double, ? extends ISeriesPoint<Date, Double>>> decodeInputSeriesMap(Map<String, String> inputMap) { Map<String, ISeries<Date, Double, ? extends ISeriesPoint<Date, Double>>> inputSeriesMap = new HashMap<String, ISeries<Date, Double, ? extends ISeriesPoint<Date, Double>>>(); for (Map.Entry<String, String> inputNameEntry : inputMap.entrySet()) { ISeries<Date, Double, ? extends ISeriesPoint<Date, Double>> inputSeries = marketDataManager.getSeries(inputNameEntry.getValue()); inputSeriesMap.put(inputNameEntry.getKey(), inputSeries); } return inputSeriesMap; } }