/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.integration.analyticservice; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.Lifecycle; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.core.config.ConfigSource; import com.opengamma.core.position.Trade; import com.opengamma.engine.marketdata.spec.MarketData; import com.opengamma.engine.view.ViewComputationResultModel; import com.opengamma.engine.view.ViewDefinition; import com.opengamma.engine.view.ViewDeltaResultModel; import com.opengamma.engine.view.ViewProcessor; import com.opengamma.engine.view.client.ViewClient; import com.opengamma.engine.view.client.ViewResultMode; import com.opengamma.engine.view.execution.ExecutionOptions; import com.opengamma.engine.view.execution.ViewExecutionOptions; import com.opengamma.engine.view.listener.AbstractViewResultListener; import com.opengamma.id.ExternalId; import com.opengamma.id.ObjectId; import com.opengamma.id.UniqueId; import com.opengamma.id.VersionCorrection; import com.opengamma.livedata.UserPrincipal; import com.opengamma.master.portfolio.ManageablePortfolio; import com.opengamma.master.portfolio.ManageablePortfolioNode; import com.opengamma.master.portfolio.PortfolioDocument; import com.opengamma.master.portfolio.PortfolioMaster; import com.opengamma.master.position.ManageablePosition; import com.opengamma.master.position.ManageableTrade; import com.opengamma.master.position.PositionDocument; import com.opengamma.master.position.PositionMaster; import com.opengamma.util.ArgumentChecker; /** * Analytic service server */ public class AnalyticServiceServer implements TradeListener, Lifecycle { /** Logger. */ private static final Logger s_logger = LoggerFactory.getLogger(AnalyticServiceServer.class); private final ViewProcessor _viewProcessor; private final PositionMaster _positionMaster; private final PortfolioMaster _portfolioMaster; private final ConfigSource _configSource; private ObjectId _portfolioId; private UniqueId _viewId; private String _viewName; private UserPrincipal _user; private ViewClient _viewClient; private AnalyticResultReceiver _analyticResultReceiver; private final ReentrantLock _updateLock = new ReentrantLock(); private final ViewExecutionOptions _viewExecutionOptions = ExecutionOptions.infinite(MarketData.live()); private final boolean _usePrivateProcess = true; private String _providerIdName; private TradeProducer _tradeProducer; private final ExecutorService _tradeUpdaterExecutor = Executors.newSingleThreadExecutor(); private final AtomicBoolean _isRunning = new AtomicBoolean(false); public AnalyticServiceServer(final ViewProcessor viewProcessor, final PositionMaster positionMaster, final PortfolioMaster portfolioMaster, final ConfigSource configSource) { ArgumentChecker.notNull(viewProcessor, "view processor"); ArgumentChecker.notNull(portfolioMaster, "portfolioMaster"); ArgumentChecker.notNull(positionMaster, "positionMaster"); ArgumentChecker.notNull(configSource, "configSource"); _viewProcessor = viewProcessor; _positionMaster = positionMaster; _portfolioMaster = portfolioMaster; _configSource = configSource; } /** * Gets the user. * @return the user */ public UserPrincipal getUser() { return _user; } /** * Sets the user. * @param user the user */ public void setUser(UserPrincipal user) { _user = user; } /** * Gets the viewProcessor. * @return the viewProcessor */ public ViewProcessor getViewProcessor() { return _viewProcessor; } /** * Gets the positionMaster. * @return the positionMaster */ public PositionMaster getPositionMaster() { return _positionMaster; } /** * Gets the portfolioMaster. * @return the portfolioMaster */ public PortfolioMaster getPortfolioMaster() { return _portfolioMaster; } /** * Gets the configSource. * @return the configSource */ public ConfigSource getConfigSource() { return _configSource; } public String getProviderIdName() { return _providerIdName; } public void setProviderIdName(String providerIdName) { this._providerIdName = providerIdName; } @Override public void tradeReceived(Trade trade) { s_logger.debug("Trade {} received", trade); if (trade != null) { _tradeUpdaterExecutor.submit(new TradeUpdaterTask(trade)); } } /** * Gets the tradeProducer. * @return the tradeProducer */ public TradeProducer getTradeProducer() { return _tradeProducer; } /** * Sets the tradeProducer. * @param tradeProducer the tradeProducer */ public void setTradeProducer(TradeProducer tradeProducer) { _tradeProducer = tradeProducer; } @Override public synchronized void start() { if (getViewName() == null) { throw new OpenGammaRuntimeException("Can not start analytic server because ViewName is missing"); } if (getTradeProducer() == null) { throw new OpenGammaRuntimeException("Can not start analytic server because TradeProducer is missing"); } ViewDefinition viewDefinition = getConfigSource().getLatestByName(ViewDefinition.class, getViewName()); if (viewDefinition == null) { throw new OpenGammaRuntimeException("Can not start analytic server because view [" + getViewName() + "] can not be loaded"); } _portfolioId = viewDefinition.getPortfolioId().getObjectId(); _viewId = viewDefinition.getUniqueId(); setUpViewClient(); _tradeProducer.addTradeListener(this); _isRunning.set(true); } private void setUpViewClient() { _updateLock.lock(); try { s_logger.debug("creating a view client to obtain view result"); _viewClient = _viewProcessor.createViewClient(getUser()); _viewClient.setResultMode(ViewResultMode.FULL_ONLY); _viewClient.setResultListener(new AbstractViewResultListener() { @Override public UserPrincipal getUser() { return getUser(); } @Override public void cycleCompleted(ViewComputationResultModel fullResult, ViewDeltaResultModel deltaResult) { if (_analyticResultReceiver != null) { _analyticResultReceiver.analyticReceived(fullResult.getAllResults()); } } }); _viewClient.attachToViewProcess(_viewId, _viewExecutionOptions, _usePrivateProcess); s_logger.debug("view client attached ready to serve results"); } finally { _updateLock.unlock(); } } @Override public synchronized void stop() { _tradeUpdaterExecutor.shutdownNow(); if (_tradeProducer != null) { _tradeProducer.removeTradeListener(this); _tradeProducer = null; } if (_viewClient != null) { _viewClient.pause(); _viewClient.shutdown(); _viewClient = null; } _isRunning.set(false); } @Override public synchronized boolean isRunning() { return _isRunning.get(); } /** * Gets the analyticResultReceiver. * @return the analyticResultReceiver */ public AnalyticResultReceiver getAnalyticResultReceiver() { return _analyticResultReceiver; } /** * Sets the analyticResultReceiver. * @param analyticResultReceiver the analyticResultReceiver */ public void setAnalyticResultReceiver(AnalyticResultReceiver analyticResultReceiver) { _analyticResultReceiver = analyticResultReceiver; } /** * Gets the viewName. * @return the viewName */ public String getViewName() { return _viewName; } /** * Sets the viewName. * @param viewName the viewName */ public void setViewName(String viewName) { _viewName = viewName; } private class TradeUpdaterTask implements Runnable { private final Trade _trade; public TradeUpdaterTask(Trade trade) { _trade = trade; } @Override public void run() { PortfolioDocument portfolioDocument = getPortfolioMaster().get(_portfolioId, VersionCorrection.LATEST); s_logger.debug("Updating portfolio {} with {}", portfolioDocument.getUniqueId(), _trade); ManageablePortfolio portfolio = portfolioDocument.getPortfolio(); ManageablePortfolioNode root = portfolio.getRootNode(); ManageablePosition position = new ManageablePosition(); position.getSecurityLink().setExternalId(_trade.getSecurityLink().getExternalId()); position.setQuantity(_trade.getQuantity()); String providerIdStr = _trade.getAttributes().get(getProviderIdName()); ManageableTrade manageableTrade = new ManageableTrade(_trade); if (providerIdStr != null) { ExternalId providerId = ExternalId.parse(providerIdStr); position.setProviderId(providerId); manageableTrade.setProviderId(providerId); } position.addTrade(manageableTrade); PositionDocument addedPosition = getPositionMaster().add(new PositionDocument(position)); root.addPosition(addedPosition.getUniqueId()); PortfolioDocument currentPortfolio = getPortfolioMaster().update(new PortfolioDocument(portfolio)); s_logger.info("Portfolio ID {} updated", currentPortfolio.getUniqueId()); restartViewCalculation(); } } private void restartViewCalculation() { _updateLock.lock(); try { s_logger.debug("kick starting computation"); if (_viewClient != null) { _viewClient.detachFromViewProcess(); _viewClient.attachToViewProcess(_viewId, _viewExecutionOptions, _usePrivateProcess); s_logger.debug("view client shut down"); } } finally { _updateLock.unlock(); } } }