/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * <p> * Please see distribution for license. */ package com.opengamma.strata.report.framework.expression; import static com.opengamma.strata.collect.Guavate.toImmutableList; import java.util.List; import java.util.Set; import com.google.common.collect.ImmutableSet; import com.opengamma.strata.basics.CalculationTarget; import com.opengamma.strata.calc.Column; import com.opengamma.strata.calc.Measure; import com.opengamma.strata.calc.runner.CalculationFunctions; import com.opengamma.strata.collect.result.FailureReason; import com.opengamma.strata.collect.result.Result; import com.opengamma.strata.product.GenericSecurityTrade; import com.opengamma.strata.product.Position; import com.opengamma.strata.product.Product; import com.opengamma.strata.product.ProductTrade; import com.opengamma.strata.product.Security; import com.opengamma.strata.product.SecurityTrade; import com.opengamma.strata.product.Trade; import com.opengamma.strata.report.ReportCalculationResults; /** * Wraps a set of {@link ReportCalculationResults} and exposes the contents of a single row. */ class ResultsRow { /** The results used to generate a report. */ private final ReportCalculationResults results; /** The index of the row in the result whose data is exposed by this object. */ private final int rowIndex; /** * Returns a new instance exposing the data from a single row in the results. * * @param results the results used to generate a report * @param rowIndex the index of the row in the result whose data is exposed by this object */ ResultsRow(ReportCalculationResults results, int rowIndex) { this.results = results; this.rowIndex = rowIndex; } //------------------------------------------------------------------------- /** * Returns the target from the row. * * @return the target from the row */ CalculationTarget getTarget() { return results.getTargets().get(rowIndex); } /** * Returns the position from the row. * * @return the position from the row */ Result<Position> getPosition() { CalculationTarget target = getTarget(); if (target instanceof Position) { return Result.success((Position) target); } return Result.failure(FailureReason.INVALID, "Calculaton target is not a position"); } /** * Returns the trade from the row. * * @return the trade from the row */ Result<Trade> getTrade() { CalculationTarget target = getTarget(); if (target instanceof Trade) { return Result.success((Trade) target); } return Result.failure(FailureReason.INVALID, "Calculaton target is not a trade"); } /** * Returns the product from the row. * <p> * This returns a successful result where the trade associated with the row * implements {@link ProductTrade}. * * @return the product from the row */ Result<Product> getProduct() { CalculationTarget target = getTarget(); if (target instanceof SecurityTrade) { SecurityTrade idTrade = (SecurityTrade) target; target = idTrade.resolveSecurity(results.getReferenceData()); } if (target instanceof ProductTrade) { return Result.success(((ProductTrade) target).getProduct()); } if (target instanceof Trade) { return Result.failure(FailureReason.INVALID, "Trade does not contain a product"); } return Result.failure(FailureReason.INVALID, "Calculaton target is not a trade"); } /** * Returns the security from the row. * <p> * This returns a successful result where the trade associated with the row * implements {@link GenericSecurityTrade}. * * @return the security from the row */ Result<Security> getSecurity() { CalculationTarget target = getTarget(); if (target instanceof SecurityTrade) { SecurityTrade secTrade = (SecurityTrade) target; Security security = results.getReferenceData().getValue(secTrade.getSecurityId()); return Result.success(security); } if (target instanceof GenericSecurityTrade) { GenericSecurityTrade secTrade = (GenericSecurityTrade) target; return Result.success(secTrade.getSecurity()); } if (target instanceof Trade) { return Result.failure(FailureReason.INVALID, "Trade does not contain a security"); } return Result.failure(FailureReason.INVALID, "Calculaton target is not a trade"); } //------------------------------------------------------------------------- /** * Returns the result of calculating the named measure for the trade in the row. * * @param measureName the name of the measure * @return the result of calculating the named measure for the trade in the row */ Result<?> getResult(String measureName) { List<String> validMeasureNames = measureNames(results.getTargets().get(rowIndex), results.getCalculationFunctions()); if (!validMeasureNames.contains(measureName)) { return Result.failure( FailureReason.INVALID, "Invalid measure name: {}. Valid measure names: {}", measureName, validMeasureNames); } try { Column column = Column.of(Measure.of(measureName)); int columnIndex = results.getColumns().indexOf(column); if (columnIndex == -1) { return Result.failure( FailureReason.INVALID, "Measure not found in results: '{}'. Valid measure names: {}", measureName, validMeasureNames); } Result<?> result = results.getCalculationResults().get(rowIndex, columnIndex); if (result.isFailure() && result.getFailure().getReason() == FailureReason.ERROR) { return Result.failure( FailureReason.INVALID, "Unable to calculate measure '{}'. Reason: {}", measureName, validMeasureNames, result.getFailure().getMessage()); } return result; } catch (IllegalArgumentException ex) { return Result.failure( FailureReason.INVALID, "Unable to calculate measure '{}'. Reason: {}. Valid measure names: {}", measureName, ex.getMessage(), validMeasureNames); } } // determine the available measures static List<String> measureNames(CalculationTarget target, CalculationFunctions calculationFunctions) { Set<Measure> validMeasures = calculationFunctions.findFunction(target) .map(fn -> fn.supportedMeasures()) .orElse(ImmutableSet.of()); return validMeasures.stream() .map(Measure::getName) .sorted() .collect(toImmutableList()); } }