/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.function;
import java.util.Collection;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Sets;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.marketdata.manipulator.function.StructureManipulator;
import com.opengamma.engine.value.ComputedValue;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValuePropertyNames;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueSpecification;
/**
* A function that takes in a structure (e.g. yield curve, volatility surface) and produces a modified version of the original as output.
* <p>
* The manipulation to be performed is specified by an implementation of the {@link StructureManipulator} interface. The particular instance to be used will be obtained as a FunctionParameter via the
* executionContext passed in through the execute method.
*/
public final class StructureManipulationFunction extends IntrinsicFunction {
private static final Logger s_logger = LoggerFactory.getLogger(StructureManipulationFunction.class);
/**
* Shared instance.
*/
public static final StructureManipulationFunction INSTANCE = new StructureManipulationFunction();
/**
* Preferred identifier this function will be available in a repository as.
*/
public static final String UNIQUE_ID = "StructureManipulator";
/**
* The expected name of the parameter containing the {@link StructureManipulator} class.
*/
public static final String EXPECTED_PARAMETER_NAME = "STRUCTURE_MANIPULATOR";
/**
* Private constructor to prevent external instantiation. The {@link #INSTANCE} should be used instead.
*/
private StructureManipulationFunction() {
super(UNIQUE_ID);
}
/**
* Execute the function, performing a manipulation of the structured data which will come in via the inputs parameter. The manipulation to actually undertake will be defined by a
* {@link StructureManipulator} instance passed in through the executionContext. If no manipulator is available the inputs are passed through unaffected (apart from a change to the value
* specification to ensure they are still valid).
*
* @param executionContext execution context for the function, via which the parameters can be obtained
* @param inputs the inputs to the function
* @param target the target
* @param desiredValues the values expected to be produced
* @return a set of computed values corresponding to the desired values
*/
@Override
public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) {
final StructureManipulator<Object> structureManipulator;
final FunctionParameters parameters = executionContext.getFunctionParameters();
if (parameters instanceof SimpleFunctionParameters) {
final SimpleFunctionParameters functionParameters = (SimpleFunctionParameters) parameters;
structureManipulator = functionParameters.getValue(EXPECTED_PARAMETER_NAME);
} else {
structureManipulator = null;
}
final Collection<ComputedValue> inputValues = inputs.getAllValues();
// Only one requirement is expected, but cope with multiple ones just in case
final Set<ComputedValue> result = Sets.newHashSetWithExpectedSize(inputValues.size());
for (ComputedValue inputValue : inputValues) {
final Object inputValueObject = inputValue.getValue();
final Object outputValueObject;
if ((inputValueObject != null) && (structureManipulator != null) && structureManipulator.getExpectedType().isAssignableFrom(inputValueObject.getClass())) {
outputValueObject = structureManipulator.execute(inputValueObject, inputValue.getSpecification(), executionContext);
s_logger.debug("changed value for target {} from {} to {}", target, inputValueObject, outputValueObject);
} else {
outputValueObject = inputValueObject;
}
final ValueSpecification inputValueSpec = inputValue.getSpecification();
final ValueProperties inputProperties = inputValueSpec.getProperties();
final String inputFunction = inputProperties.getStrictValue(ValuePropertyNames.FUNCTION);
final ValueProperties outputProperties = inputProperties.copy().withoutAny(ValuePropertyNames.FUNCTION).with(ValuePropertyNames.FUNCTION, inputFunction + UNIQUE_ID).get();
final ValueSpecification outputValueSpec = new ValueSpecification(inputValueSpec.getValueName(), inputValueSpec.getTargetSpecification(), outputProperties);
result.add(new ComputedValue(outputValueSpec, outputValueObject));
}
return result;
}
@Override
public boolean canHandleMissingInputs() {
return false;
}
}