Package com.opengamma.web.analytics

Source Code of com.opengamma.web.analytics.PortfolioGridStructure

/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.web.analytics;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.opengamma.core.position.Portfolio;
import com.opengamma.core.position.PortfolioNode;
import com.opengamma.core.position.Position;
import com.opengamma.core.position.Trade;
import com.opengamma.core.position.impl.PortfolioMapper;
import com.opengamma.core.position.impl.PortfolioMapperFunction;
import com.opengamma.core.security.Security;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.management.ValueMappings;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.engine.view.ViewCalculationConfiguration;
import com.opengamma.engine.view.ViewDefinition;
import com.opengamma.engine.view.compilation.CompiledViewDefinition;
import com.opengamma.financial.security.FinancialSecurity;
import com.opengamma.id.UniqueId;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Triple;

/**
* The structure of the grid that displays portfolio data and analytics. Contains the column definitions and
* the portfolio tree structure.
*/
public class PortfolioGridStructure extends MainGridStructure {

  /** Definition of the view driving the grid. */
  private final ViewDefinition _viewDef;
  /** Meta data for exploded child columns, keyed by the specification of the parent column. */
  private final Map<ColumnSpecification, SortedSet<ColumnMeta>> _inlineColumnMeta;
  /** Rows in the grid. */
  private final List<PortfolioGridRow> _rows;

  /* package */ PortfolioGridStructure(List<PortfolioGridRow> rows,
                                       GridColumnGroup fixedColumns,
                                       GridColumnGroups nonFixedColumns,
                                       AnalyticsNode rootNode,
                                       TargetLookup targetLookup,
                                       UnversionedValueMappings valueMappings,
                                       ViewDefinition viewDef) {
    this(rows, fixedColumns, nonFixedColumns, rootNode, targetLookup, valueMappings, viewDef,
         Collections.<ColumnSpecification, SortedSet<ColumnMeta>>emptyMap());
  }

  /* package */ PortfolioGridStructure(List<PortfolioGridRow> rows,
                                       GridColumnGroup fixedColumns,
                                       GridColumnGroups nonFixedColumns,
                                       AnalyticsNode rootNode,
                                       TargetLookup targetLookup,
                                       UnversionedValueMappings valueMappings,
                                       ViewDefinition viewDef,
                                       Map<ColumnSpecification, SortedSet<ColumnMeta>> inlineColumnMeta) {
    super(fixedColumns, nonFixedColumns, targetLookup, rootNode, valueMappings);
    ArgumentChecker.notNull(rows, "rows");
    ArgumentChecker.notNull(inlineColumnMeta, "inlineColumnCounts");
    _inlineColumnMeta = inlineColumnMeta;
    _rows = rows;
    _viewDef = viewDef;
  }

  /* package */ static PortfolioGridStructure create(Portfolio portfolio, UnversionedValueMappings valueMappings) {
    ArgumentChecker.notNull(valueMappings, "valueMappings");
    // TODO these can be empty, not used any more
    List<PortfolioGridRow> rows = buildRows(portfolio);
    TargetLookup targetLookup = new TargetLookup(valueMappings, rows);
    AnalyticsNode rootNode = AnalyticsNode.portfolioRoot(portfolio);
    return new PortfolioGridStructure(rows,
                                      GridColumnGroup.empty(),
                                      GridColumnGroups.empty(),
                                      rootNode,
                                      targetLookup,
                                      valueMappings,
                                      new ViewDefinition("empty", "dummy"));
  }

  /* package */ PortfolioGridStructure withUpdatedRows(Portfolio portfolio) {
    AnalyticsNode rootNode = AnalyticsNode.portfolioRoot(portfolio);
    List<PortfolioGridRow> rows = buildRows(portfolio);
    GridColumnGroup fixedColumns = buildFixedColumns(rows);
    TargetLookup targetLookup = new TargetLookup(super.getValueMappings(), rows);
    List<GridColumnGroup> analyticsColumns = buildAnalyticsColumns(_viewDef, targetLookup);
    GridColumnGroups nonFixedColumns = new GridColumnGroups(analyticsColumns);
    return new PortfolioGridStructure(rows, fixedColumns, nonFixedColumns, rootNode, targetLookup,
                                      super.getValueMappings(), _viewDef);
  }

  /* package */ PortfolioGridStructure withUpdatedStructure(CompiledViewDefinition compiledViewDef, Portfolio portfolio) {
    AnalyticsNode rootNode = AnalyticsNode.portfolioRoot(portfolio);
    List<PortfolioGridRow> rows = buildRows(portfolio);
    GridColumnGroup fixedColumns = buildFixedColumns(rows);
    UnversionedValueMappings valueMappings = new UnversionedValueMappings(compiledViewDef);
    TargetLookup targetLookup = new TargetLookup(valueMappings, rows);
    ViewDefinition viewDef = compiledViewDef.getViewDefinition();
    List<GridColumnGroup> analyticsColumns = buildAnalyticsColumns(viewDef, targetLookup);
    GridColumnGroups nonFixedColumns = new GridColumnGroups(analyticsColumns);
    return new PortfolioGridStructure(rows, fixedColumns, nonFixedColumns, rootNode, targetLookup, valueMappings, viewDef);
  }

  /* package */ PortfolioGridStructure withUpdatedStructure(ResultsCache cache) {
    Map<ColumnSpecification, SortedSet<ColumnMeta>> inlineColumnMeta = Maps.newHashMap();
    for (GridColumn column : getColumnStructure().getColumns()) {
      ColumnSpecification colSpec = column.getSpecification();
      if (Inliner.isDisplayableInline(column.getUnderlyingType(), column.getSpecification())) {
        // ordered set of the union of the column metadata for the whole set. need this to figure out how many unique
        // columns are required
        SortedSet<ColumnMeta> allColumnMeta = Sets.newTreeSet();
        // traverse every result in the column and get the column metadata
        for (Iterator<Pair<String, ValueSpecification>> it = getTargetLookup().getTargetsForColumn(colSpec); it.hasNext(); ) {
          Pair<String, ValueSpecification> target = it.next();
          if (target != null) {
            ResultsCache.Result result = cache.getResult(target.getFirst(), target.getSecond(), column.getType());
            Object value = result.getValue();
            allColumnMeta.addAll(Inliner.columnMeta(value));
          }
        }
        if (!allColumnMeta.isEmpty()) {
          inlineColumnMeta.put(colSpec, allColumnMeta);
        }
      }
    }
    // TODO implement equals() and always return a new instance? conceptually a bit neater but less efficient
    if (!inlineColumnMeta.equals(_inlineColumnMeta)) {
      List<GridColumnGroup> analyticsColumns = buildAnalyticsColumns(_viewDef, getTargetLookup(), inlineColumnMeta);
      return new PortfolioGridStructure(_rows,
                                        buildFixedColumns(_rows),
                                        new GridColumnGroups(analyticsColumns),
                                        getRootNode(),
                                        getTargetLookup(),
                                        getValueMappings(),
                                        _viewDef,
                                        inlineColumnMeta);
    } else {
      return this;
    }
  }

  /* package */ PortfolioGridStructure withNode(AnalyticsNode node) {
    return new PortfolioGridStructure(_rows, getFixedColumns(), getNonFixedColumns(), node, getTargetLookup(),
                                      super.getValueMappings(), _viewDef);
  }

  /* package */ static GridColumnGroup buildFixedColumns(List<PortfolioGridRow> rows) {
    GridColumn labelColumn = new GridColumn("Name", "", null, new PortfolioLabelRenderer(rows));
    return new GridColumnGroup("fixed", ImmutableList.of(labelColumn), false);
  }

  /* package */ static List<GridColumnGroup> buildAnalyticsColumns(ViewDefinition viewDef, TargetLookup targetLookup) {
    return buildAnalyticsColumns(viewDef, targetLookup, Collections.<ColumnSpecification, SortedSet<ColumnMeta>>emptyMap());
  }

  /**
   * @param viewDef The view definition
   * @return Columns for displaying calculated analytics data, one group per calculation configuration
   */
  /* package */ static List<GridColumnGroup> buildAnalyticsColumns(ViewDefinition viewDef,
                                                                   TargetLookup targetLookup,
                                                                   Map<ColumnSpecification, SortedSet<ColumnMeta>> inlineColumnMeta) {
    List<GridColumnGroup> columnGroups = Lists.newArrayList();
    Set<Triple<String, String, ValueProperties>> columnSpecs = Sets.newHashSet();
    for (ViewCalculationConfiguration calcConfig : viewDef.getAllCalculationConfigurations()) {
      List<ColumnSpecification> allSpecs = Lists.newArrayList();
      for (ViewCalculationConfiguration.Column column : calcConfig.getColumns()) {
        allSpecs.add(new ColumnSpecification(calcConfig.getName(),
                                             column.getValueName(),
                                             column.getProperties(),
                                             column.getHeader()));
      }
      for (Pair<String, ValueProperties> output : calcConfig.getAllPortfolioRequirements()) {
        allSpecs.add(new ColumnSpecification(calcConfig.getName(), output.getFirst(), output.getSecond()));
      }
      List<GridColumn> columns = Lists.newArrayList();
      for (ColumnSpecification columnSpec : allSpecs) {
        Class<?> columnType = ValueTypes.getTypeForValueName(columnSpec.getValueName());
        // ensure column isn't a duplicate. can't use a set of col specs because we need to treat columns as duplicates
        // even if they have different headers
        if (columnSpecs.add(Triple.of(columnSpec.getCalcConfigName(), columnSpec.getValueName(), columnSpec.getValueProperties()))) {
          SortedSet<ColumnMeta> meta = inlineColumnMeta.get(columnSpec);
          if (meta == null) { // column can't be inlined
            columns.add(GridColumn.forSpec(columnSpec, columnType, targetLookup));
          } else {
            int inlineIndex = 0;
            for (ColumnMeta columnMeta : meta) {
              String header;
              if (inlineIndex++ == 0) {
                header = columnSpec.getHeader() + " / " + columnMeta.getHeader();
              } else {
                header = columnMeta.getHeader();
              }
              columns.add(GridColumn.forSpec(header,
                                             columnSpec,
                                             columnMeta.getType(),
                                             columnMeta.getUnderlyingType(),
                                             targetLookup,
                                             columnMeta.getKey(),
                                             inlineIndex));
            }
          }
        }
      }
      if (!columns.isEmpty()) {
        columnGroups.add(new GridColumnGroup(calcConfig.getName(), columns, true));
      }
    }
    return columnGroups;
  }

  /* package */ static List<PortfolioGridRow> buildRows(final Portfolio portfolio) {
    if (portfolio == null) {
      return Collections.emptyList();
    }
    PortfolioMapperFunction<List<PortfolioGridRow>> targetFn = new PortfolioMapperFunction<List<PortfolioGridRow>>() {

      @Override
      public List<PortfolioGridRow> apply(PortfolioNode node) {
        ComputationTargetSpecification target =
            new ComputationTargetSpecification(ComputationTargetType.PORTFOLIO_NODE, node.getUniqueId());
        String nodeName;
        // if the parent ID is null it's the root node
        if (node.getParentNodeId() == null) {
          // the root node is called "Root" which isn't any use for displaying in the UI, use the portfolio name instead
          nodeName = portfolio.getName();
        } else {
          nodeName = node.getName();
        }
        return Lists.newArrayList(new PortfolioGridRow(target, nodeName, node.getUniqueId()));
      }

      @Override
      public List<PortfolioGridRow> apply(PortfolioNode parentNode, Position position) {
        ComputationTargetSpecification nodeSpec = ComputationTargetSpecification.of(parentNode);
        // TODO I don't think toLatest() will do long term. resolution time available on the result model
        UniqueId positionId = position.getUniqueId();
        ComputationTargetSpecification target = nodeSpec.containing(ComputationTargetType.POSITION,
                                                                    positionId.toLatest());
        Security security = position.getSecurity();
        List<PortfolioGridRow> rows = Lists.newArrayList();
        UniqueId nodeId = parentNode.getUniqueId();
        if (isFungible(position.getSecurity())) {
          rows.add(new PortfolioGridRow(target, security.getName(), security.getUniqueId(), nodeId, positionId));
          for (Trade trade : position.getTrades()) {
            String tradeDate = trade.getTradeDate().toString();
            rows.add(new PortfolioGridRow(ComputationTargetSpecification.of(trade),
                                          tradeDate,
                                          security.getUniqueId(),
                                          nodeId,
                                          positionId,
                                          trade.getUniqueId()));
          }
        } else {
          Collection<Trade> trades = position.getTrades();
          if (trades.isEmpty()) {
            rows.add(new PortfolioGridRow(target, security.getName(), security.getUniqueId(), nodeId, positionId));
          } else {
            // there is never more than one trade on a position in an OTC security
            UniqueId tradeId = trades.iterator().next().getUniqueId();
            rows.add(new PortfolioGridRow(target, security.getName(), security.getUniqueId(), nodeId, positionId, tradeId));
          }
        }
        return rows;
      }
    };
    List<List<PortfolioGridRow>> rows = PortfolioMapper.map(portfolio.getRootNode(), targetFn);
    Iterable<PortfolioGridRow> flattenedRows = Iterables.concat(rows);
    return Lists.newArrayList(flattenedRows);
  }

  /**
   * @param security A security
   * @return true if the security is fungible, false if OTC
   */
  private static boolean isFungible(Security security) {
    if (security instanceof FinancialSecurity) {     
      Boolean isOTC = ((FinancialSecurity) security).accept(new OtcSecurityVisitor());
      if (isOTC == null) {
        return false;
      }
      return !isOTC;
    } else {
      return false;
    }
  }
}
TOP

Related Classes of com.opengamma.web.analytics.PortfolioGridStructure

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.