/** * 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.Collections; import java.util.Set; import com.opengamma.sesame.config.FunctionModelConfig; import com.opengamma.sesame.engine.ComponentMap; import com.opengamma.sesame.function.FunctionMetadata; import com.opengamma.sesame.function.InvokableFunction; import com.opengamma.sesame.graph.convert.ArgumentConverter; import com.opengamma.util.ArgumentChecker; /** * Lightweight representation of the tree of functions for a single output. * <p> * Each node in the tree is represented by {@link FunctionModelNode}. * There are nodes for each function that must be created and for each * parameter passed to the constructor of the function. * Proxy nodes may be added to insert additional behaviour. * An error node can be added if there is a problem. * TODO this class has static and instance methods called build(). that's not good */ public final class FunctionModel { // TODO replace Set<Class<?>> component types with AvailableComponents // TODO wrap FunctionModelConfig and AvailableComponents in a class for easier decoration by scenarios. name? // TODO wrap FunctionModelConfig and ComponentMap in a class for easier decoration by scenarios. name? /** The root node of the tree of functions and dependencies. */ private final FunctionModelNode _root; /** The function meta-data for the root function. */ private final FunctionMetadata _rootMetadata; /** * @param root the root node, not null * @param rootMetadata the meta-data, not null */ private FunctionModel(FunctionModelNode root, FunctionMetadata rootMetadata) { _root = root; _rootMetadata = rootMetadata; } //------------------------------------------------------------------------- /** * Builds the function defined by this model. * * @param builder the builder to use, not null * @param components the map of components, not null * @return the function created from this model, not null * @throws GraphBuildException if the function cannot be built */ public InvokableFunction build(FunctionBuilder builder, ComponentMap components) { Object receiver = builder.create(_root, components); return _rootMetadata.getInvokableFunction(receiver); } //------------------------------------------------------------------------- /** * Gets the root node of the function model tree. * * @return the root node */ public FunctionModelNode getRoot() { return _root; } /** * Checks if this model is valid such that a function can be constructed. * * @return true if this model is valid */ public boolean isValid() { return _root.isValid(); } //------------------------------------------------------------------------- /** * Pretty prints this model without proxies. * * @return the tree structure, not null */ public String prettyPrint() { return prettyPrint(false); } /** * Pretty prints this model. * * @param showProxies true to include proxy nodes * @return the tree structure, not null */ public String prettyPrint(boolean showProxies) { return _root.prettyPrint(showProxies); } //------------------------------------------------------------------------- /** * Builds a {@link FunctionModel} representing a function implementation and its dependencies. * * @param function The function's metadata * @param config Configuration specifying the implementations and arguments for building the function and its dependencies * @param availableComponents Component types available for injecting into function implementations * @param nodeDecorators For inserting nodes in the model between functions to add functionality, e.g. caching, * logging, tracing * @return A model of the function implementation and its dependencies */ public static FunctionModel forFunction(FunctionMetadata function, FunctionModelConfig config, Set<Class<?>> availableComponents, NodeDecorator... nodeDecorators) { NodeDecorator nodeDecorator = CompositeNodeDecorator.compose(nodeDecorators); FunctionModelNode node = FunctionModelNode.create(function.getDeclaringType(), config, availableComponents, nodeDecorator); return new FunctionModel(node, function); } /** * Builds a {@link FunctionModel} representing a function implementation and its dependencies. * * @param function The function's metadata * @param config Configuration specifying the implementations and arguments for building the function and its dependencies * @param availableComponents Component types available for injecting into function implementations * @param nodeDecorator For inserting nodes in the model between functions to add functionality, e.g. caching, * logging, tracing * @return A model of the function implementation and its dependencies */ public static FunctionModel forFunction(FunctionMetadata function, FunctionModelConfig config, Set<Class<?>> availableComponents, NodeDecorator nodeDecorator, ArgumentConverter argumentConverter) { FunctionModelNode node = FunctionModelNode.create(function.getDeclaringType(), config, availableComponents, nodeDecorator, argumentConverter); return new FunctionModel(node, function); } /** * Builds a {@link FunctionModel} representing a function implementation and its dependencies. * This is suitable for building functions that require user specified constructor arguments but don't require * components provided by the system. * @param function The function's metadata * @param config Configuration specifying the implementations and arguments for building the function and its * dependencies * logging, tracing * @return A model of the function implementation and its dependencies */ public static FunctionModel forFunction(FunctionMetadata function, FunctionModelConfig config) { FunctionModelNode node = FunctionModelNode.create(function.getDeclaringType(), config, Collections.<Class<?>>emptySet(), NodeDecorator.IDENTITY); return new FunctionModel(node, function); } /** * Builds a {@link FunctionModel} representing a function implementation and its dependencies. * This is only suitable for building the simplest of functions that require no arguments or components. * @param function The function's metadata * @return A model of the function implementation and its dependencies */ public static FunctionModel forFunction(FunctionMetadata function) { FunctionModelNode node = FunctionModelNode.create(function.getDeclaringType(), FunctionModelConfig.EMPTY, Collections.<Class<?>>emptySet(), NodeDecorator.IDENTITY); return new FunctionModel(node, function); } /** * Builds a function model from metadata and an existing model node. * This is useful for the case where * * @param function the function's metadata * @param functionNode model node for building the function instance * @return a model built using the metadata and node */ public static FunctionModel forFunction(FunctionMetadata function, FunctionModelNode functionNode) { ArgumentChecker.notNull(function, "function"); ArgumentChecker.notNull(functionNode, "functionNode"); Class<?> functionType = function.getDeclaringType(); Class<?> nodeType = functionNode.getType(); if (!functionType.isAssignableFrom(nodeType)) { throw new IllegalArgumentException("Function type " + functionType.getName() + " is not compatible with node type " + nodeType.getName()); } return new FunctionModel(functionNode, function); } /** * Creates a {@link FunctionModelNode} for a function and its dependencies, builds it and returns the constructed * function object. * * @param functionType the type of the function, can be an interface or implementation class * @param config configuration for building the function and its dependencies * @param componentMap components available for injecting into the function and its dependencies * @param nodeDecorators for inserting nodes between functions to add functionality, e.g. caching, * logging, tracing * @param <T> The type of the function * @return The constructed function, not null */ public static <T> T build(Class<T> functionType, FunctionModelConfig config, ComponentMap componentMap, NodeDecorator... nodeDecorators) { return build(functionType, config, componentMap, new FunctionBuilder(), nodeDecorators); } /** * Creates a {@link FunctionModelNode} for a function and its dependencies, builds it and returns the constructed * function object. * * @param functionType the type of the function, can be an interface or implementation class * @param config configuration for building the function and its dependencies * @param componentMap components available for injecting into the function and its dependencies * @param functionBuilder builds the function instances * @param nodeDecorators for inserting nodes between functions to add functionality, e.g. caching, * logging, tracing * @param <T> The type of the function * @return The constructed function, not null */ public static <T> T build(Class<T> functionType, FunctionModelConfig config, ComponentMap componentMap, FunctionBuilder functionBuilder, NodeDecorator... nodeDecorators) { NodeDecorator nodeDecorator = CompositeNodeDecorator.compose(nodeDecorators); FunctionModelNode node = FunctionModelNode.create(functionType, config, componentMap.getComponentTypes(), nodeDecorator); Object function = functionBuilder.create(node, componentMap); return functionType.cast(function); } /** * Creates a {@link FunctionModelNode} for a function and its dependencies, builds it and returns the constructed function object. * This is suitable for building functions that require user specified constructor arguments but don't require * components provided by the system. * @param functionType The type of the function, can be an interface or implementation class * @param config Configuration for building the function and its dependencies * @param <T> The type of the function * @return The constructed function, not null */ public static <T> T build(Class<T> functionType, FunctionModelConfig config) { return build(functionType, config, ComponentMap.EMPTY); } /** * Creates a {@link FunctionModelNode} for a function and its dependencies, builds it and returns the constructed function object. * This is only suitable for building the simplest of functions that require no arguments or components. * @param functionType The type of the function, can be an interface or implementation class * @param <T> The type of the function * @return The constructed function, not null */ public static <T> T build(Class<T> functionType) { return build(functionType, FunctionModelConfig.EMPTY); } }