com.opengamma.integration.viewer.status.impl.ViewStatusCalculationTask.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.integration.viewer.status.impl.ViewStatusCalculationTask.java

Source

/**
 * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
 * 
 * Please see distribution for license.
 */
package com.opengamma.integration.viewer.status.impl;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Instant;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.config.impl.ConfigItem;
import com.opengamma.core.position.Portfolio;
import com.opengamma.core.position.Position;
import com.opengamma.core.position.PositionSource;
import com.opengamma.core.position.Trade;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.calcnode.MissingValue;
import com.opengamma.engine.marketdata.spec.MarketDataSpecification;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ComputedValueResult;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.engine.view.ViewCalculationConfiguration;
import com.opengamma.engine.view.ViewCalculationResultModel;
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.compilation.CompiledViewCalculationConfiguration;
import com.opengamma.engine.view.compilation.CompiledViewDefinition;
import com.opengamma.engine.view.cycle.ViewCycleMetadata;
import com.opengamma.engine.view.execution.ExecutionOptions;
import com.opengamma.engine.view.execution.ViewCycleExecutionOptions;
import com.opengamma.engine.view.listener.AbstractViewResultListener;
import com.opengamma.financial.aggregation.CurrenciesAggregationFunction;
import com.opengamma.financial.aggregation.PortfolioAggregator;
import com.opengamma.financial.tool.ToolContext;
import com.opengamma.id.UniqueId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.integration.viewer.status.ViewStatus;
import com.opengamma.livedata.UserPrincipal;
import com.opengamma.master.config.ConfigMaster;
import com.opengamma.master.config.ConfigMasterUtils;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.GUIDGenerator;
import com.opengamma.util.tuple.Pair;

/**
 * View status calculation task
 */
public class ViewStatusCalculationTask implements Callable<PerViewStatusResult> {

    private final class ViewStatusResultListener extends AbstractViewResultListener {
        private final CountDownLatch _latch;
        private final PerViewStatusResult _statusResult;
        private final ViewDefinition _viewDefinition;
        private AtomicLong _count = new AtomicLong(0);

        private ViewStatusResultListener(CountDownLatch latch, PerViewStatusResult statusResult,
                ViewDefinition viewDefinition) {
            _latch = latch;
            _statusResult = statusResult;
            _viewDefinition = viewDefinition;
        }

        @Override
        public UserPrincipal getUser() {
            return _user;
        }

        @Override
        public void viewDefinitionCompiled(CompiledViewDefinition compiledViewDefinition,
                boolean hasMarketDataPermissions) {
            s_logger.error("View definition compiled");
            CompiledViewCalculationConfiguration compiledCalculationConfiguration = compiledViewDefinition
                    .getCompiledCalculationConfiguration(DEFAULT_CALC_CONFIG);
            Map<ValueSpecification, Set<ValueRequirement>> terminalOutputs = compiledCalculationConfiguration
                    .getTerminalOutputSpecifications();
            for (ValueSpecification valueSpec : terminalOutputs.keySet()) {
                ComputationTargetType computationTargetType = valueSpec.getTargetSpecification().getType();
                if (isValidTargetType(computationTargetType)) {
                    UniqueId uniqueId = valueSpec.getTargetSpecification().getUniqueId();
                    String currency = getCurrency(uniqueId, computationTargetType);
                    if (currency != null) {
                        _statusResult.put(new ViewStatusKeyBean(_securityType, valueSpec.getValueName(), currency,
                                computationTargetType.getName()), ViewStatus.NO_VALUE);
                    } else {
                        s_logger.error("Discarding result as NULL return as Currency for id: {} targetType:{}",
                                uniqueId, computationTargetType);
                    }
                }
            }
        }

        @Override
        public void viewDefinitionCompilationFailed(final Instant valuationTime, final Exception exception) {
            s_logger.debug("View definition {} failed to initialize", _viewDefinition);
            try {
                processGraphFailResult(_statusResult);
            } finally {
                _latch.countDown();
            }
        }

        public void cycleStarted(ViewCycleMetadata cycleInfo) {
            s_logger.debug("Cycle started");
        }

        @Override
        public void cycleExecutionFailed(ViewCycleExecutionOptions executionOptions, Exception exception) {
            s_logger.debug("Cycle execution failed", exception);
        }

        @Override
        public void processCompleted() {
            s_logger.debug("Process completed");
        }

        @Override
        public void processTerminated(boolean executionInterrupted) {
            s_logger.debug("Process terminated");
        }

        @Override
        public void clientShutdown(Exception e) {
            s_logger.debug("Client shutdown");
        }

        @Override
        public void cycleFragmentCompleted(ViewComputationResultModel fullResult,
                ViewDeltaResultModel deltaResult) {
            s_logger.debug("cycle fragment completed");
        }

        @Override
        public void cycleCompleted(final ViewComputationResultModel fullResult,
                final ViewDeltaResultModel deltaResult) {
            s_logger.debug("cycle {} completed", _count.get());
            if (_count.getAndIncrement() > 5) {
                processStatusResult(fullResult, _statusResult);
                _latch.countDown();
            }
        }
    }

    private static final String MIXED_CURRENCY = "MIXED_CURRENCY";
    private static final Logger s_logger = LoggerFactory.getLogger(ViewStatusCalculationTask.class);

    private static final String DEFAULT_CALC_CONFIG = "Default";

    private final String _securityType;
    private final Set<String> _valueRequirementNames;
    private final UniqueId _portfolioId;
    private final UserPrincipal _user;
    private final ToolContext _toolContext;
    private final CurrenciesAggregationFunction _currenciesAggrFunction;
    private final Map<UniqueId, String> _targetCurrenciesCache = Maps.newConcurrentMap();
    private final MarketDataSpecification _marketDataSpecification;

    public ViewStatusCalculationTask(ToolContext toolcontext, UniqueId portfolioId, UserPrincipal user,
            String securityType, Collection<String> valueRequirementNames,
            MarketDataSpecification marketDataSpecification) {
        ArgumentChecker.notNull(portfolioId, "portfolioId");
        ArgumentChecker.notNull(securityType, "securityType");
        ArgumentChecker.notNull(valueRequirementNames, "valueRequirementNames");
        ArgumentChecker.notNull(user, "user");
        ArgumentChecker.notNull(toolcontext, "toolcontext");
        ArgumentChecker.notNull(marketDataSpecification, "marketDataSpecification");

        _portfolioId = portfolioId;
        _user = user;
        _securityType = securityType;
        _valueRequirementNames = ImmutableSet.copyOf(valueRequirementNames);
        _toolContext = toolcontext;
        _currenciesAggrFunction = new CurrenciesAggregationFunction(_toolContext.getSecuritySource());
        _marketDataSpecification = marketDataSpecification;
    }

    @Override
    public PerViewStatusResult call() throws Exception {
        s_logger.debug("Start calculating result for security:{} with values{}", _securityType,
                Sets.newTreeSet(_valueRequirementNames).toString());

        final PerViewStatusResult statusResult = new PerViewStatusResult(_securityType);
        //No need to do any work if there are no ValueRequirements to compute
        if (_valueRequirementNames.isEmpty()) {
            return statusResult;
        }
        final ViewDefinition viewDefinition = createViewDefinition();
        final ViewProcessor viewProcessor = _toolContext.getViewProcessor();
        final ViewClient client = viewProcessor.createViewClient(_user);

        final CountDownLatch latch = new CountDownLatch(1);
        client.setResultListener(new ViewStatusResultListener(latch, statusResult, viewDefinition));
        client.attachToViewProcess(viewDefinition.getUniqueId(),
                ExecutionOptions.infinite(_marketDataSpecification));

        try {
            s_logger.info("main thread waiting");
            if (!latch.await(30, TimeUnit.SECONDS)) {
                s_logger.error("Timed out waiting for {}", viewDefinition);
            }
        } catch (final InterruptedException ex) {
            throw new OpenGammaRuntimeException("Interrupted while waiting for " + viewDefinition, ex);
        }
        client.detachFromViewProcess();
        removeViewDefinition(viewDefinition);
        s_logger.debug("PerViewStatusResult for securityType:{} is {}", _securityType, statusResult);
        return statusResult;
    }

    protected boolean isValidTargetType(final ComputationTargetType computationTargetType) {
        if (ComputationTargetType.POSITION.isCompatible(computationTargetType)
                || ComputationTargetType.PORTFOLIO.isCompatible(computationTargetType)
                || ComputationTargetType.PORTFOLIO_NODE.isCompatible(computationTargetType)
                || ComputationTargetType.TRADE.isCompatible(computationTargetType)) {
            return true;
        }
        return false;
    }

    private void removeViewDefinition(ViewDefinition viewDefinition) {
        s_logger.debug("Removing ViewDefintion with id: {}", viewDefinition.getUniqueId());
        ConfigMaster configMaster = _toolContext.getConfigMaster();
        configMaster.remove(viewDefinition.getUniqueId().getObjectId());
        s_logger.debug("ViewDefinition {} removed", viewDefinition.getUniqueId());
    }

    private ViewDefinition createViewDefinition() {
        final ViewDefinition viewDefinition = new ViewDefinition("VS_VIEW_" + GUIDGenerator.generate().toString(),
                _portfolioId, _user);
        viewDefinition.setMaxDeltaCalculationPeriod(500L);
        viewDefinition.setMaxFullCalculationPeriod(500L);
        viewDefinition.setMinDeltaCalculationPeriod(500L);
        viewDefinition.setMinFullCalculationPeriod(500L);

        ViewCalculationConfiguration defaultCalConfig = new ViewCalculationConfiguration(viewDefinition,
                DEFAULT_CALC_CONFIG);
        for (String requiredOutput : _valueRequirementNames) {
            defaultCalConfig.addPortfolioRequirementName(_securityType, requiredOutput);
        }
        viewDefinition.addViewCalculationConfiguration(defaultCalConfig);
        return storeViewDefinition(viewDefinition);
    }

    private ViewDefinition storeViewDefinition(final ViewDefinition viewDefinition) {
        ConfigItem<ViewDefinition> config = ConfigItem.of(viewDefinition, viewDefinition.getName(),
                ViewDefinition.class);
        config = ConfigMasterUtils.storeByName(_toolContext.getConfigMaster(), config);
        return config.getValue();
    }

    private void processGraphFailResult(final PerViewStatusResult statusResult) {
        PositionSource positionSource = _toolContext.getPositionSource();
        Portfolio portfolio = positionSource.getPortfolio(_portfolioId, VersionCorrection.LATEST);
        List<Position> positions = PortfolioAggregator.flatten(portfolio);
        Set<String> currencies = Sets.newHashSet();
        for (Position position : positions) {
            if (position.getSecurity() == null) {
                position.getSecurityLink().resolve(_toolContext.getSecuritySource());
            }
            if (position.getSecurity() != null && _securityType.equals(position.getSecurity().getSecurityType())) {
                currencies.add(getCurrency(position.getUniqueId(), ComputationTargetType.POSITION));
            }
        }
        for (String valueName : _valueRequirementNames) {
            for (String currency : currencies) {
                statusResult.put(new ViewStatusKeyBean(_securityType, valueName, currency,
                        ComputationTargetType.POSITION.getName()), ViewStatus.GRAPH_FAIL);
            }
        }
    }

    private void processStatusResult(ViewComputationResultModel fullResult, PerViewStatusResult statusResult) {
        ViewCalculationResultModel calculationResult = fullResult.getCalculationResult(DEFAULT_CALC_CONFIG);
        Collection<ComputationTargetSpecification> allTargets = calculationResult.getAllTargets();
        for (ComputationTargetSpecification targetSpec : allTargets) {
            ComputationTargetType targetType = targetSpec.getSpecification().getType();
            if (isValidTargetType(targetType)) {
                Map<Pair<String, ValueProperties>, ComputedValueResult> values = calculationResult
                        .getValues(targetSpec);
                for (Map.Entry<Pair<String, ValueProperties>, ComputedValueResult> valueEntry : values.entrySet()) {
                    String valueName = valueEntry.getKey().getFirst();
                    String currency = getCurrency(targetSpec.getUniqueId(), targetType);
                    s_logger.debug("{} currency returned for id:{} targetType:{}", currency,
                            targetSpec.getUniqueId(), targetType);
                    if (currency != null) {
                        ComputedValueResult computedValue = valueEntry.getValue();
                        if (isGoodValue(computedValue)) {
                            statusResult.put(
                                    new ViewStatusKeyBean(_securityType, valueName, currency, targetType.getName()),
                                    ViewStatus.VALUE);
                        }
                    } else {
                        s_logger.error("Discarding result as NULL return as Currency for id: {} targetType:{}",
                                targetSpec.getUniqueId(), targetType);
                    }
                }
            }
        }
    }

    private String getCurrency(UniqueId uniqueId, ComputationTargetType computationTargetType) {
        synchronized (_targetCurrenciesCache) {
            String currency = _targetCurrenciesCache.get(uniqueId);
            if (currency == null) {
                if (ComputationTargetType.PORTFOLIO_NODE.isCompatible(computationTargetType)
                        || ComputationTargetType.PORTFOLIO.isCompatible(computationTargetType)) {
                    currency = MIXED_CURRENCY;
                } else if (ComputationTargetType.POSITION.isCompatible(computationTargetType)) {
                    PositionSource positionSource = _toolContext.getPositionSource();
                    Position position = positionSource.getPosition(uniqueId);
                    if (position.getSecurity() == null) {
                        position.getSecurityLink().resolve(_toolContext.getSecuritySource());
                    }
                    if (position.getSecurity() != null) {
                        currency = _currenciesAggrFunction.classifyPosition(position);
                    }
                } else if (ComputationTargetType.TRADE.isCompatible(computationTargetType)) {
                    PositionSource positionSource = _toolContext.getPositionSource();
                    Trade trade = positionSource.getTrade(uniqueId);
                    if (trade.getSecurity() == null) {
                        trade.getSecurityLink().resolve(_toolContext.getSecuritySource());
                    }
                    if (trade.getSecurity() != null) {
                        currency = CurrenciesAggregationFunction.classifyBasedOnSecurity(trade.getSecurity(),
                                _toolContext.getSecuritySource());
                    }
                }
            }
            if (currency == null) {
                currency = CurrenciesAggregationFunction.NO_CURRENCY;
            }
            _targetCurrenciesCache.put(uniqueId, currency);
            return currency;
        }
    }

    private boolean isGoodValue(final ComputedValueResult computedValue) {
        if (computedValue == null || computedValue.getValue() == null
                || StringUtils.EMPTY.equals(computedValue.getValue())) {
            return false;
        } else {
            return !(computedValue.getValue() instanceof MissingValue);
        }
    }

}