/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.marketdata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.engine.ComputationTargetResolver;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.marketdata.OverrideOperation;
import com.opengamma.engine.marketdata.OverrideOperationCompiler;
import com.opengamma.engine.target.ComputationTargetReferenceVisitor;
import com.opengamma.engine.target.ComputationTargetRequirement;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.financial.expression.CommonSynthetics;
import com.opengamma.financial.expression.ELExpressionParser;
import com.opengamma.financial.expression.UserExpression;
import com.opengamma.financial.expression.UserExpressionParser;
import com.opengamma.id.ExternalIdBundle;
/**
* Implementation of {@link OverrideOperationCompiler} that allows market data overrides to be expressed as EL expressions.
*/
public class MarketDataELCompiler implements OverrideOperationCompiler {
private static final Logger s_logger = LoggerFactory.getLogger(MarketDataELCompiler.class);
private final class Evaluator implements OverrideOperation {
private final UserExpression _expr;
private final ComputationTargetResolver.AtVersionCorrection _resolver;
public Evaluator(final UserExpression expr, final ComputationTargetResolver.AtVersionCorrection resolver) {
_expr = expr;
_resolver = resolver;
}
private UserExpression getExpr() {
return _expr;
}
@Override
public Object apply(final ValueRequirement requirement, final Object original) {
UserExpressionParser.setResolver(_resolver);
s_logger.debug("Applying {} to {}", _expr, requirement);
final UserExpression.Evaluator eval = getExpr().evaluator();
eval.setVariable("x", original);
if (requirement.getTargetReference().getType().isTargetType(ComputationTargetType.SECURITY)) {
requirement.getTargetReference().accept(new ComputationTargetReferenceVisitor<Void>() {
@Override
public Void visitComputationTargetRequirement(final ComputationTargetRequirement requirement) {
eval.setVariable("security", UserExpressionParser.resolve(ComputationTargetType.SECURITY, requirement.getIdentifiers()));
return null;
}
@Override
public Void visitComputationTargetSpecification(final ComputationTargetSpecification specification) {
eval.setVariable("security", UserExpressionParser.resolve(ComputationTargetType.SECURITY, specification.getUniqueId()));
return null;
}
});
} else if (requirement.getTargetReference().getType().isTargetType(ComputationTargetType.PRIMITIVE)) {
requirement.getTargetReference().accept(new ComputationTargetReferenceVisitor<Void>() {
@Override
public Void visitComputationTargetRequirement(final ComputationTargetRequirement requirement) {
final ExternalIdBundle bundle = requirement.getIdentifiers();
eval.setVariable("externalIds", bundle);
if (bundle.size() == 1) {
eval.setVariable("externalId", bundle.iterator().next());
}
return null;
}
@Override
public Void visitComputationTargetSpecification(final ComputationTargetSpecification specification) {
eval.setVariable("uniqueId", specification.getUniqueId());
return null;
}
});
}
eval.setVariable("value", requirement.getValueName());
final Object result = eval.evaluate();
UserExpressionParser.setResolver(null);
if (result == UserExpression.NA) {
s_logger.debug("Evaluation failed - using original {}", original);
return original;
} else {
s_logger.debug("Evaluation of {} to {}", original, result);
return result;
}
}
}
private final UserExpressionParser _parser;
public MarketDataELCompiler() {
_parser = new ELExpressionParser();
try {
_parser.setFunction("Curve", "parallelShift", MarketDataELFunctions.class.getMethod("parallelShiftCurve", Object.class, Double.TYPE));
_parser.setFunction("Curve", "pointShift", MarketDataELFunctions.class.getMethod("pointShiftCurve", Object.class, Double.TYPE, Double.TYPE));
_parser.setFunction("Security", "get", MarketDataELFunctions.class.getMethod("getSecurity", Object.class));
_parser.setFunction("FX", "isRate", MarketDataELFunctions.class.getMethod("isFXRate", Object.class));
_parser.setFunction("FX", "multiplier", MarketDataELFunctions.class.getMethod("getFXMultiplier", Object.class, Double.TYPE));
CommonSynthetics.configureParser(_parser);
} catch (final Exception ex) {
throw new OpenGammaRuntimeException("Caught", ex);
}
}
@Override
public OverrideOperation compile(final String operation, final ComputationTargetResolver.AtVersionCorrection resolver) {
final UserExpression expr = getParser().parse(operation);
return new Evaluator(expr, resolver);
}
private UserExpressionParser getParser() {
return _parser;
}
}