Package com.opengamma.web.server

Source Code of com.opengamma.web.server.RequirementBasedWebViewGrid

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

import it.unimi.dsi.fastutil.longs.LongArraySet;
import it.unimi.dsi.fastutil.longs.LongSet;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.cometd.bayeux.server.LocalSession;
import org.cometd.bayeux.server.ServerSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.opengamma.engine.ComputationTargetResolver;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.calcnode.MissingValue;
import com.opengamma.engine.depgraph.DependencyGraph;
import com.opengamma.engine.depgraph.DependencyGraphExplorer;
import com.opengamma.engine.resource.EngineResourceReference;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ComputedValue;
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.ViewComputationResultModel;
import com.opengamma.engine.view.ViewDefinition;
import com.opengamma.engine.view.ViewTargetResultModel;
import com.opengamma.engine.view.client.ViewClient;
import com.opengamma.engine.view.compilation.CompiledViewDefinition;
import com.opengamma.engine.view.cycle.ViewCycle;
import com.opengamma.id.UniqueId;
import com.opengamma.util.monitor.OperationTimer;
import com.opengamma.util.tuple.Pair;
import com.opengamma.web.server.conversion.ResultConverter;
import com.opengamma.web.server.conversion.ResultConverterCache;

/**
* An abstract base class for dynamically-structured, requirement-based grids.
*/
public abstract class RequirementBasedWebViewGrid extends WebViewGrid {

  private static final Logger s_logger = LoggerFactory.getLogger(RequirementBasedWebViewGrid.class);
  private static final String GRID_STRUCTURE_ROOT_CHANNEL = "/gridStructure";

  private final String _columnStructureChannel;
  private final RequirementBasedGridStructure _gridStructure;
  private final String _nullCellValue;
  private final ComputationTargetResolver _computationTargetResolver;

  // Column-based state: few entries expected so using an array set
  private final LongSet _historyOutputs = new LongArraySet();

  // Cell-based state
  private final ConcurrentMap<WebGridCell, WebViewDepGraphGrid> _depGraphGrids = new ConcurrentHashMap<WebGridCell, WebViewDepGraphGrid>();

  protected RequirementBasedWebViewGrid(
      String name, ViewClient viewClient, CompiledViewDefinition compiledViewDefinition, List<ComputationTargetSpecification> targets,
      Set<? extends ComputationTargetType> targetTypes, ResultConverterCache resultConverterCache,
      LocalSession local, ServerSession remote, String nullCellValue,
      ComputationTargetResolver computationTargetResolver) {
    super(name, viewClient, resultConverterCache, local, remote);

    _columnStructureChannel = GRID_STRUCTURE_ROOT_CHANNEL + "/" + name + "/columns";
    List<RequirementBasedColumnKey> requirements = getRequirements(compiledViewDefinition.getViewDefinition(), targetTypes);
    _gridStructure = new RequirementBasedGridStructure(compiledViewDefinition, targetTypes, requirements, targets);
    _nullCellValue = nullCellValue;
    _computationTargetResolver = computationTargetResolver;
  }

  //-------------------------------------------------------------------------

  public void processTargetResult(final int rowId, ComputationTargetSpecification target, ViewTargetResultModel resultModel, Long resultTimestamp) {
    Map<String, Object> valuesToSend = createTargetResult(rowId);
    for (Integer unsatisfiedColId : getGridStructure().getUnsatisfiedCells(rowId)) {
      valuesToSend.put(Integer.toString(unsatisfiedColId), null);
    }
    // Whether or not the row is in the viewport, we may have to store history
    if (resultModel != null) {
      for (String calcConfigName : resultModel.getCalculationConfigurationNames()) {
        for (ComputedValue value : resultModel.getAllValues(calcConfigName)) {
          if (value.getValue() instanceof MissingValue) {
            // Ignore the value -- before PLAT-1765 we wouldn't have seen a result at all
            continue;
          }
          ValueSpecification specification = value.getSpecification();
          Collection<WebViewGridColumn> columns = getGridStructure().getColumns(calcConfigName, specification);
          if (columns == null) {
            // Expect a column for every value
            s_logger.warn("Could not find column for calculation configuration {} with value specification {}", calcConfigName, specification);
            continue;
          }
          Object originalValue = value.getValue();
          for (WebViewGridColumn column : columns) {
            int colId = column.getId();
            WebGridCell cell = WebGridCell.of(rowId, colId);
            ResultConverter<Object> converter = originalValue != null ? getConverter(column, value.getSpecification().getValueName(), originalValue.getClass()) : null;
            Map<String, Object> cellData = processCellValue(cell, specification, originalValue, resultTimestamp, converter);
            if (cellData != null) {
              valuesToSend.put(Integer.toString(colId), cellData);
            }
          }
        }
      }
    }
    getRemoteSession().deliver(getLocalSession(), getUpdateChannel(), valuesToSend, null);
  }

  private Map<String, Object> createTargetResult(Integer rowId) {
    Map<String, Object> valuesToSend = new HashMap<String, Object>();
    valuesToSend.put("rowId", rowId);
    return valuesToSend;
  }

  public void processDepGraphs(long resultTimestamp) {
    if (_depGraphGrids.isEmpty()) {
      return;
    }

    // TODO: this may not be the cycle corresponding to the result - some tracking of cycle IDs required
    EngineResourceReference<? extends ViewCycle> cycleReference = getViewClient().createLatestCycleReference();
    if (cycleReference == null) {
      // Unable to get a cycle reference - perhaps no cycle has completed since enabling introspection
      s_logger.warn("Unable to get a cycle reference");
      return;
    }
    try {
      for (WebViewDepGraphGrid depGraphGrid : _depGraphGrids.values()) {
        Object gridStructure = null;
        if (!depGraphGrid.isInit()) {
          String calcConfigName = depGraphGrid.getParentCalcConfigName();
          ValueSpecification valueSpecification = depGraphGrid.getParentValueSpecification();
          DependencyGraphExplorer explorer = cycleReference.get().getCompiledViewDefinition().getDependencyGraphExplorer(calcConfigName);
          DependencyGraph subgraph = explorer.getSubgraphProducing(valueSpecification);
          if (subgraph == null) {
            s_logger.warn("No subgraph producing value specification {}", valueSpecification);
            continue;
          }
          if (depGraphGrid.init(subgraph, calcConfigName, valueSpecification)) {
            gridStructure = depGraphGrid.getInitialJsonGridStructure();
          }
        }
        Map<String, Object> depGraph = depGraphGrid.processViewCycle(cycleReference.get(), resultTimestamp);
        Object depGraphMessage = null;
        if (gridStructure != null) {
          Map<String, Object> structureMessage = new HashMap<String, Object>();
          structureMessage.put("grid", gridStructure);
          structureMessage.put("update", depGraph);
          depGraphMessage = structureMessage;
        } else {
          depGraphMessage = depGraph;
        }
        Map<String, Object> valuesToSend = createTargetResult(depGraphGrid.getParentGridCell().getRowId());
        Map<String, Object> columnMessage = new HashMap<String, Object>();
        columnMessage.put("dg", depGraphMessage);
        valuesToSend.put(Integer.toString(depGraphGrid.getParentGridCell().getColumnId()), columnMessage);
        getRemoteSession().deliver(getLocalSession(), getUpdateChannel(), valuesToSend, null);
      }
    } finally {
      cycleReference.release();
    }
  }

  @SuppressWarnings("unchecked")
  private ResultConverter<Object> getConverter(WebViewGridColumn column, String valueName, Class<?> valueType) {
    // Ensure the converter is cached against the value name before sending the column details
    ResultConverter<Object> converter = (ResultConverter<Object>) getConverterCache().getAndCacheConverter(valueName, valueType);
    if (!column.isTypeKnown()) {
      sendColumnDetails(Collections.singleton(column));
    }
    return converter;
  }

  private void sendColumnDetails(Collection<WebViewGridColumn> columnDetails) {
    getRemoteSession().deliver(getLocalSession(), _columnStructureChannel, getJsonColumnStructures(columnDetails), null);
  }

  @Override
  public Map<String, Object> getInitialJsonGridStructure() {
    Map<String, Object> gridStructure = super.getInitialJsonGridStructure();
    gridStructure.put("columns", getJsonColumnStructures(getGridStructure().getColumns()));
    return gridStructure;
  }

  @Override
  protected List<Object> getInitialJsonRowStructures() {
    final ComputationTargetSpecification[] targets = getGridStructure().getTargets();
    final List<Object> rowStructures = new ArrayList<Object>(targets.length);
    for (int i = 0; i < targets.length; i++) {
      UniqueId target = targets[i].getUniqueId();
      Map<String, Object> rowDetails = new HashMap<String, Object>();
      rowDetails.put("rowId", i);
      addRowDetails(target, i, rowDetails);
      rowStructures.add(rowDetails);
    }
    return rowStructures;
  }

  private Map<String, Object> getJsonColumnStructures(Collection<WebViewGridColumn> columns) {
    Map<String, Object> columnStructures = new HashMap<String, Object>(columns.size());
    for (WebViewGridColumn columnDetails : columns) {
      columnStructures.put(Integer.toString(columnDetails.getId()), getJsonColumnStructure(columnDetails));
    }
    return columnStructures;
  }

  private Map<String, Object> getJsonColumnStructure(WebViewGridColumn column) {
    Map<String, Object> detailsToSend = new HashMap<String, Object>();
    long colId = column.getId();
    detailsToSend.put("colId", colId);
    detailsToSend.put("header", column.getHeader());
    detailsToSend.put("description", column.getValueName() + ":\n" + column.getDescription());
    detailsToSend.put("nullValue", _nullCellValue);

    String resultType = getConverterCache().getKnownResultTypeName(column.getValueName());
    if (resultType != null) {
      column.setTypeKnown(true);
      detailsToSend.put("dataType", resultType);

      // Hack - the client should decide which columns it requires history for, taking into account the capabilities of
      // the renderer.
      if (resultType.equals("DOUBLE")) {
        addHistoryOutput(column.getId());
      }
    }
    return detailsToSend;
  }

  protected abstract void addRowDetails(UniqueId target, int rowId, Map<String, Object> details);

  //-------------------------------------------------------------------------
  protected RequirementBasedGridStructure getGridStructure() {
    return _gridStructure;
  }

  private ComputationTargetResolver getComputationTargetResolver() {
    return _computationTargetResolver;
  }

  private void addHistoryOutput(long colId) {
    _historyOutputs.add(colId);
  }

  @Override
  protected boolean isHistoryOutput(WebGridCell cell) {
    return _historyOutputs.contains(cell.getColumnId());
  }

  //-------------------------------------------------------------------------
  public WebViewGrid setIncludeDepGraph(WebGridCell cell, boolean includeDepGraph) {
    if (includeDepGraph) {
      String gridName = getName() + ".depgraph-" + cell.getRowId() + "-" + cell.getColumnId();
      OperationTimer timer = new OperationTimer(s_logger, "depgraph");
      Pair<String, ValueSpecification> columnMappingPair = getGridStructure().findCellSpecification(cell, getViewClient().getLatestCompiledViewDefinition());
      s_logger.debug("includeDepGraph took {}", timer.finished());
      WebViewDepGraphGrid grid = new WebViewDepGraphGrid(gridName, getViewClient(), getConverterCache(),
          getLocalSession(), getRemoteSession(), cell, columnMappingPair.getFirst(), columnMappingPair.getSecond(), getComputationTargetResolver());
      _depGraphGrids.putIfAbsent(cell, grid);
      return grid;
    } else {
      WebViewDepGraphGrid grid = _depGraphGrids.remove(cell);
      return grid;
    }
  }

  public void setDepGraphViewport(WebGridCell cell, SortedMap<Integer, Long> viewportMap) {
    WebViewDepGraphGrid grid = _depGraphGrids.get(cell);
    if (grid == null) {
      return;
    }
    grid.setViewport(viewportMap);
  }

  //------------------------------------------------------------------------- 
  @Override
  protected String[][] getCsvColumnHeaders() {
    Collection<WebViewGridColumn> columns = getGridStructure().getColumns();
    int additionalColumns = getAdditionalCsvColumnCount();
    int columnCount = columns.size() + additionalColumns;
    String[] header1 = new String[columnCount];
    String[] header2 = new String[columnCount];
    supplementCsvColumnHeaders(header1);
    int offset = getCsvDataColumnOffset();
    for (WebViewGridColumn column : columns) {
      header1[offset + column.getId()] = column.getHeader();
      header2[offset + column.getId()] = column.getDescription();
    }
    return new String[][] {header1, header2 };
  }

  @Override
  protected String[][] getCsvRows(ViewComputationResultModel result) {
    String[][] rows = new String[getGridStructure().getTargets().length][];
    int columnCount = getGridStructure().getColumns().size() + getAdditionalCsvColumnCount();
    int offset = getCsvDataColumnOffset();
    for (ComputationTargetSpecification target : result.getAllTargets()) {
      final int[] rowIds = getGridStructure().getRowIds(target);
      if (rowIds == null) {
        continue;
      }
      ViewTargetResultModel resultModel = result.getTargetResult(target);
      for (int rowId : rowIds) {
        String[] values = new String[columnCount];
        supplementCsvRowData(rowId, target, values);
        rows[rowId] = values;
        for (String calcConfigName : resultModel.getCalculationConfigurationNames()) {
          for (ComputedValue value : resultModel.getAllValues(calcConfigName)) {
            Object originalValue = value.getValue();
            if (originalValue == null) {
              continue;
            }
            ValueSpecification specification = value.getSpecification();
            Collection<WebViewGridColumn> columns = getGridStructure().getColumns(calcConfigName, specification);
            if (columns == null) {
              // Expect a column for every value
              s_logger.warn("Could not find column for calculation configuration {} with value specification {}", calcConfigName, specification);
              continue;
            }
            for (WebViewGridColumn column : columns) {
              int colId = column.getId();
              ResultConverter<Object> converter = getConverter(column, value.getSpecification().getValueName(), originalValue.getClass());
              values[offset + colId] = converter.convertToText(getConverterCache(), value.getSpecification(), originalValue);
            }
          }
        }
      }
    }
    return rows;
  }

  protected int getAdditionalCsvColumnCount() {
    return 0;
  }

  protected int getCsvDataColumnOffset() {
    return 0;
  }

  protected void supplementCsvColumnHeaders(String[] headers) {
  }

  protected void supplementCsvRowData(int rowId, ComputationTargetSpecification target, String[] row) {
  }

  //-------------------------------------------------------------------------

  private static List<RequirementBasedColumnKey> getRequirements(ViewDefinition viewDefinition, Set<? extends ComputationTargetType> targetTypes) {
    List<RequirementBasedColumnKey> result = new ArrayList<RequirementBasedColumnKey>();
    for (ViewCalculationConfiguration calcConfig : viewDefinition.getAllCalculationConfigurations()) {
      String calcConfigName = calcConfig.getName();
      if (targetTypes.contains(ComputationTargetType.POSITION) || targetTypes.contains(ComputationTargetType.PORTFOLIO_NODE)) {
        for (Pair<String, ValueProperties> portfolioOutput : calcConfig.getAllPortfolioRequirements()) {
          String valueName = portfolioOutput.getFirst();
          ValueProperties constraints = portfolioOutput.getSecond();
          RequirementBasedColumnKey columnKey = new RequirementBasedColumnKey(calcConfigName, valueName, constraints);
          result.add(columnKey);
        }
      }

      for (ValueRequirement specificRequirement : calcConfig.getSpecificRequirements()) {
        if (!targetTypes.contains(specificRequirement.getTargetReference().getType())) {
          continue;
        }
        String valueName = specificRequirement.getValueName();
        ValueProperties constraints = specificRequirement.getConstraints();
        RequirementBasedColumnKey columnKey = new RequirementBasedColumnKey(calcConfigName, valueName, constraints);
        result.add(columnKey);
      }
    }
    return result;
  }

}
TOP

Related Classes of com.opengamma.web.server.RequirementBasedWebViewGrid

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.