/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.graph;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableMap;
import com.opengamma.sesame.engine.ComponentMap;
import com.opengamma.sesame.function.ConfigurationErrorFunction;
import com.opengamma.sesame.function.InvokableFunction;
import com.opengamma.util.ArgumentChecker;
/**
* Lightweight representation of the function models needed for a view.
* <p>
* A view is formed from a grid of cells, each of which generates a desired output.
* The function for each cell is represented by a {@link FunctionModel}.
* The complete model for all cells is represented by this class.
*/
public final class GraphModel {
/** Logger. */
private static final Logger s_logger = LoggerFactory.getLogger(GraphModel.class);
// TODO for this to be useful in the UI it needs to be map(column -> map((outputName,inputType) -> functionModel))
// it will probably be better to have a real class than a rats' nest of generics
/** Function models for portfolio output. The outer map is keyed by column name, the inner map by input type. */
private final Map<String, Map<Class<?>, FunctionModel>> _portfolioFunctionModels;
/** Function models for non-portfolio outputs, keyed by name */
private final Map<String, FunctionModel> _nonPortfolioFunctionModels;
/* package */ GraphModel(Map<String, Map<Class<?>, FunctionModel>> portfolioFunctionModels,
Map<String, FunctionModel> nonPortfolioFunctionModels) {
_portfolioFunctionModels = ArgumentChecker.notNull(portfolioFunctionModels, "portfolioFunctionModels");
_nonPortfolioFunctionModels = ArgumentChecker.notNull(nonPortfolioFunctionModels, "nonPortfolioFunctionModels");
}
/**
* Builds the graph from the model using the specified set of components.
*
* @param components the component map, not null
* @return a graph containing the built function instances, not null
*/
public Graph build(ComponentMap components, FunctionBuilder functionBuilder) {
// build the functions for the portfolio outputs
ImmutableMap.Builder<String, Map<Class<?>, InvokableFunction>> portfolioFunctions = ImmutableMap.builder();
for (Map.Entry<String, Map<Class<?>, FunctionModel>> entry : _portfolioFunctionModels.entrySet()) {
Map<Class<?>, FunctionModel> functionsByTargetId = entry.getValue();
ImmutableMap.Builder<Class<?>, InvokableFunction> columnBuilder = ImmutableMap.builder();
for (Map.Entry<Class<?>, FunctionModel> columnEntry : functionsByTargetId.entrySet()) {
Class<?> inputType = columnEntry.getKey();
FunctionModel functionModel = columnEntry.getValue();
if (functionModel.isValid()) {
columnBuilder.put(inputType, functionModel.build(functionBuilder, components));
} else {
s_logger.warn("Can't build invalid function model{}", functionModel.prettyPrint());
// put in a placeholder function that produces no output
FunctionModel noOutputFunctionModel = FunctionModel.forFunction(ConfigurationErrorFunction.METADATA);
columnBuilder.put(inputType, noOutputFunctionModel.build(functionBuilder, components));
}
}
String columnName = entry.getKey();
portfolioFunctions.put(columnName, columnBuilder.build());
}
// build the functions for the non-portfolio outputs
ImmutableMap.Builder<String, InvokableFunction> nonPortfolioFunctions = ImmutableMap.builder();
for (Map.Entry<String, FunctionModel> entry : _nonPortfolioFunctionModels.entrySet()) {
String name = entry.getKey();
FunctionModel functionModel = entry.getValue();
if (functionModel.isValid()) {
nonPortfolioFunctions.put(name, functionModel.build(functionBuilder, components));
} else {
s_logger.warn("Can't build invalid function model{}", functionModel.prettyPrint());
// put in a placeholder function that produces no output
FunctionModel noOutputFunctionModel = FunctionModel.forFunction(ConfigurationErrorFunction.METADATA);
nonPortfolioFunctions.put(name, noOutputFunctionModel.build(functionBuilder, components));
}
}
return new Graph(portfolioFunctions.build(), nonPortfolioFunctions.build());
}
/**
* Returns the {@link FunctionModel} of the function used to calculate the value in a column.
* @param columnName the name of the column
* @param inputType type of input (i.e. the security, trade or position type) for the row
* @return the function model or null if there isn't one for the specified input type
* @throws IllegalArgumentException if the column name isn't found
*/
public FunctionModel getFunctionModel(String columnName, Class<?> inputType) {
ArgumentChecker.notEmpty(columnName, "columnName");
Map<Class<?>, FunctionModel> columnFns = _portfolioFunctionModels.get(columnName);
if (columnFns == null) {
throw new IllegalArgumentException("There is no column named '" + columnName + "'");
} else {
return columnFns.get(inputType);
}
}
/**
* Returns the {@link FunctionModel} of the function used to calculate a non-portfolio output.
* @param outputName the name of the output
* @return the function model
* @throws IllegalArgumentException if the output name isn't found
*/
public FunctionModel getFunctionModel(String outputName) {
FunctionModel model = _nonPortfolioFunctionModels.get(ArgumentChecker.notEmpty(outputName, "outputName"));
if (model == null) {
throw new IllegalArgumentException("There is no output named '" + outputName + "'");
} else {
return model;
}
}
}