/** * 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.Collections; import java.util.List; import com.google.common.collect.Lists; import com.opengamma.engine.target.ComputationTargetReference; import com.opengamma.engine.value.ValueRequirement; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.tuple.Pair; import com.opengamma.util.tuple.Pairs; /** * Column structure of the grid used to display analytics data. */ /* package */ abstract class MainGridStructure implements GridStructure { /** For mapping cells to values in the results. */ private final UnversionedValueMappings _valueMappings; /** The complete column structure. */ private final GridColumnGroups _columnGroups; /** The fixed column structure. */ private final GridColumnGroup _fixedColumnGroup; /** The non fixed column structure. */ private final GridColumnGroups _nonFixedColumnGroups; /** For looking up the underlying target of a grid cell. */ private final TargetLookup _targetLookup; /** The root node of the portfolio structure. */ private final AnalyticsNode _rootNode; /* package */ MainGridStructure() { _columnGroups = GridColumnGroups.empty(); _fixedColumnGroup = GridColumnGroup.empty(); _nonFixedColumnGroups = GridColumnGroups.empty(); _valueMappings = new UnversionedValueMappings(); _targetLookup = new TargetLookup(_valueMappings, Collections.<Row>emptyList()); _rootNode = null; } // TODO refactor this to pass in columns instead of column keys? // column would need to return its key (null for static and blotter columns) // could pass all columns in a single List<GridColumnGroup> or GridColumnGroups instance /* package */ MainGridStructure(GridColumnGroup fixedColumns, GridColumnGroups nonFixedColumns, TargetLookup targetLookup, AnalyticsNode rootNode, UnversionedValueMappings valueMappings) { ArgumentChecker.notNull(targetLookup, "targetLookup"); ArgumentChecker.notNull(nonFixedColumns, "nonFixedColumns"); ArgumentChecker.notNull(fixedColumns, "fixedColumns"); ArgumentChecker.notNull(valueMappings, "valueMappings"); List<GridColumnGroup> columnGroups = Lists.newArrayList(fixedColumns); columnGroups.addAll(nonFixedColumns.getGroups()); _rootNode = rootNode; _columnGroups = new GridColumnGroups(columnGroups); _fixedColumnGroup = fixedColumns; _nonFixedColumnGroups = nonFixedColumns; _targetLookup = targetLookup; _valueMappings = valueMappings; } /* package */ MainGridStructure(GridColumnGroup fixedColumns, GridColumnGroups nonFixedColumns, TargetLookup targetLookup, UnversionedValueMappings valueMappings) { ArgumentChecker.notNull(targetLookup, "targetLookup"); ArgumentChecker.notNull(nonFixedColumns, "nonFixedColumns"); ArgumentChecker.notNull(fixedColumns, "fixedColumns"); ArgumentChecker.notNull(valueMappings, "valueMappings"); List<GridColumnGroup> columnGroups = Lists.newArrayList(fixedColumns); columnGroups.addAll(nonFixedColumns.getGroups()); _columnGroups = new GridColumnGroups(columnGroups); _targetLookup = targetLookup; _fixedColumnGroup = fixedColumns; _nonFixedColumnGroups = nonFixedColumns; _rootNode = null; _valueMappings = valueMappings; } /** * Returns the calculation configuration name and value specification for a cell in the grid. * @param rowIndex The row index * @param colIndex The column index * @return Pair of value spec and calculation config name. * TODO need to specify row using a stable target ID for the row to cope with dynamic aggregation */ @Override public Pair<String, ValueSpecification> getValueSpecificationForCell(int rowIndex, int colIndex) { if (rowIndex < 0 || rowIndex >= getRowCount() || colIndex < 0 || colIndex >= getColumnCount()) { throw new IllegalArgumentException("Cell is outside grid bounds: row=" + rowIndex + ", col=" + colIndex + ", rowCount=" + getRowCount() + ", colCount=" + getColumnCount()); } return _targetLookup.getTargetForCell(rowIndex, _columnGroups.getColumn(colIndex).getSpecification()); } /** * Returns the calculation configuration name and value requirement for a cell in the grid. * @param rowIndex The row index * @param colIndex The column index * @return Pair of value requirement and calculation config name. * TODO need to specify row using a stable target ID for the row to cope with dynamic aggregation */ @Override public Pair<String, ValueRequirement> getValueRequirementForCell(int rowIndex, int colIndex) { if (rowIndex < 0 || rowIndex >= getRowCount() || colIndex < 0 || colIndex >= getColumnCount()) { throw new IllegalArgumentException("Cell is outside grid bounds: row=" + rowIndex + ", col=" + colIndex + ", rowCount=" + getRowCount() + ", colCount=" + getColumnCount()); } return _targetLookup.getRequirementForCell(rowIndex, _columnGroups.getColumn(colIndex).getSpecification()); } @Override public GridColumnGroups getColumnStructure() { return _columnGroups; } @Override public GridColumnGroup getFixedColumns() { return _fixedColumnGroup; } @Override public GridColumnGroups getNonFixedColumns() { return _nonFixedColumnGroups; } @Override public int getRowCount() { return _targetLookup.getRowCount(); } @Override public int getColumnCount() { return _columnGroups.getColumnCount(); } public TargetLookup getTargetLookup() { return _targetLookup; } /** * @return The root node of the portfolio structure. */ public AnalyticsNode getRootNode() { return _rootNode; } @Override public String toString() { return "MainGridStructure [_columnGroups=" + _columnGroups + "]"; } public Pair<ViewportResults, Viewport.State> createResults(ViewportDefinition viewportDefinition, ResultsCache cache) { boolean updated = false; boolean hasData = false; List<ResultsCell> results = Lists.newArrayList(); for (GridCell cell : viewportDefinition) { GridColumn column = _columnGroups.getColumn(cell.getColumn()); ResultsCell resultsCell = column.buildResults(cell.getRow(), cell.getFormat(), cache); updated = updated || resultsCell.isUpdated(); if (resultsCell.getValue() != null) { hasData = true; } results.add(resultsCell); } Viewport.State state; if (updated) { state = Viewport.State.FRESH_DATA; } else if (hasData) { state = Viewport.State.STALE_DATA; } else { state = Viewport.State.EMPTY; } ViewportResults viewportResults = new ViewportResults(results, viewportDefinition, _columnGroups, cache.getLastCalculationDuration(), cache.getValuationTime()); return Pairs.of(viewportResults, state); } /** * @return For mapping cells to values in the results. */ protected UnversionedValueMappings getValueMappings() { return _valueMappings; } /** * A row in the grid. */ /* package */ static class Row { /** The row's target. */ private final ComputationTargetReference _target; /** The row label. */ private final String _name; /* package */ Row(ComputationTargetReference target, String name) { ArgumentChecker.notNull(target, "target"); ArgumentChecker.notNull(name, "name"); _target = target; _name = name; } /* package */ ComputationTargetReference getTarget() { return _target; } /* package */ String getName() { return _name; } @Override public String toString() { return "Row [_target=" + _target + ", _name='" + _name + '\'' + "]"; } } }