/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.function.resolver;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.engine.function.FunctionParameters;
import com.opengamma.engine.function.ParameterizedFunction;
/**
* Resolution rule transform that matches on the short name of the function.
*/
public class SimpleResolutionRuleTransform implements ResolutionRuleTransform {
/** Logger. */
private static final Logger s_logger = LoggerFactory.getLogger(SimpleResolutionRuleTransform.class);
/**
* The function transformations.
*/
private final Map<String, Action> _functionTransformations = new HashMap<String, Action>();
/**
* Gets the map of registered transformations.
* <p>
* The map is keyed by short function name, with the value being the the action to be applied.
* If multiple actions are applied, the function will be advertised by multiple new rules in
* place of the original. If a function is omitted from the set, the original rule is preserved.
*
* @return the set of transformations, not null
*/
public Map<String, Action> getFunctionTransformations() {
return Collections.unmodifiableMap(_functionTransformations);
}
//-------------------------------------------------------------------------
/**
* Suppress any rules using the given function name.
*
* @param shortFunctionName the function to suppress, not null
*/
public void suppressRule(final String shortFunctionName) {
registerAction(shortFunctionName, DontUse.INSTANCE);
}
/**
* Adjust the rules using the given function name.
*
* @param shortFunctionName the function to adjust, not null
* @param parameters the function parameters, null to use the original rule default
* @param priorityAdjustment the priority shift, null to use the original rule default
* @param computationTargetFilter the computation target filter, null to use the original rule default
*/
public void adjustRule(final String shortFunctionName, final FunctionParameters parameters, final ComputationTargetFilter computationTargetFilter, final Integer priorityAdjustment) {
registerAction(shortFunctionName, new Adjust(parameters, computationTargetFilter, priorityAdjustment));
}
private void registerAction(final String shortFunctionName, final Action action) {
final Action existing = _functionTransformations.get(shortFunctionName);
if (existing == null) {
_functionTransformations.put(shortFunctionName, action);
} else {
_functionTransformations.put(shortFunctionName, existing.with(action));
}
}
//-------------------------------------------------------------------------
@Override
public Collection<ResolutionRule> transform(final Collection<ResolutionRule> rules) {
final Collection<ResolutionRule> result = Lists.newArrayListWithCapacity(rules.size());
for (ResolutionRule rule : rules) {
final String function = rule.getParameterizedFunction().getFunction().getFunctionDefinition().getShortName();
final Action action = _functionTransformations.get(function);
if (action == null) {
s_logger.debug("Function {} has no transformation rules", function);
result.add(rule);
} else {
s_logger.debug("Applying transformation rules for function {}", function);
action.apply(rule, result);
}
}
return result;
}
//-------------------------------------------------------------------------
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof SimpleResolutionRuleTransform) {
final SimpleResolutionRuleTransform other = (SimpleResolutionRuleTransform) obj;
return _functionTransformations.equals(other._functionTransformations);
}
return false;
}
@Override
public int hashCode() {
return 0; // not intended to be hashed
}
@Override
public String toString() {
return getClass().getSimpleName() + _functionTransformations;
}
//-------------------------------------------------------------------------
/**
* Describes an action as part of a rule's transformation.
*/
public abstract static class Action {
protected abstract Action with(Action other);
protected abstract void apply(final ResolutionRule originalRule, final Collection<ResolutionRule> output);
}
//-------------------------------------------------------------------------
/**
* Describes a rule that should be suppressed.
*/
public static final class DontUse extends Action {
private static final Action INSTANCE = new DontUse();
private DontUse() {
}
@Override
protected Action with(final Action other) {
throw new OpenGammaRuntimeException("Resolution rule already marked as \"Don't use\"");
}
@Override
protected void apply(final ResolutionRule originalRule, final Collection<ResolutionRule> output) {
s_logger.debug("Discarding {}", originalRule);
}
@Override
public boolean equals(final Object o) {
return (o == this) || (o instanceof DontUse);
}
@Override
public int hashCode() {
// Not destined for hash tables
return 0;
}
@Override
public String toString() {
return "Don't use";
}
}
//-------------------------------------------------------------------------
/**
* Describes a rule that should be adjusted.
*/
public static final class Adjust extends Action {
private Integer _priorityAdjustment;
private FunctionParameters _parameters;
private ComputationTargetFilter _computationTargetFilter;
private Adjust(final FunctionParameters parameters, final ComputationTargetFilter filter, final Integer priorityAdjustment) {
_priorityAdjustment = priorityAdjustment;
_parameters = parameters;
_computationTargetFilter = filter;
}
public Integer getPriorityAdjustment() {
return _priorityAdjustment;
}
public FunctionParameters getParameters() {
return _parameters;
}
public ComputationTargetFilter getComputationTargetFilter() {
return _computationTargetFilter;
}
@Override
protected Action with(final Action other) {
return new MultipleAdjust().with(this).with(other);
}
@Override
protected void apply(final ResolutionRule originalRule, final Collection<ResolutionRule> output) {
ParameterizedFunction function = originalRule.getParameterizedFunction();
if (_parameters != null) {
function = new ParameterizedFunction(originalRule.getParameterizedFunction().getFunction(), _parameters);
}
final ComputationTargetFilter computationTargetFilter;
if (_computationTargetFilter != null) {
computationTargetFilter = _computationTargetFilter;
} else {
computationTargetFilter = originalRule.getComputationTargetFilter();
}
int priority = originalRule.getPriority();
if (_priorityAdjustment != null) {
priority += _priorityAdjustment;
}
final ResolutionRule replacement = new ResolutionRule(function, computationTargetFilter, priority);
s_logger.debug("Publishing {} in place of {}", replacement, originalRule);
output.add(replacement);
}
@Override
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Adjust)) {
return false;
}
final Adjust other = (Adjust) o;
return ObjectUtils.equals(_parameters, other._parameters)
&& ObjectUtils.equals(_computationTargetFilter, other._computationTargetFilter)
&& ObjectUtils.equals(_priorityAdjustment, other._priorityAdjustment);
}
@Override
public int hashCode() {
// Not destined for hash tables
return 0;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Adjust[");
boolean comma = false;
if (_parameters != null) {
sb.append("Parameters=").append(_parameters);
comma = true;
}
if (_computationTargetFilter != null) {
if (comma) {
sb.append(',');
} else {
comma = true;
}
sb.append("ComputationTargetFilter=").append(_computationTargetFilter);
}
if (_priorityAdjustment != null) {
if (comma) {
sb.append(',');
}
sb.append("PriorityAdjustment=").append(_priorityAdjustment);
}
return sb.append(']').toString();
}
}
//-------------------------------------------------------------------------
/**
* Describes a set of adjustments for a single rule.
*/
public static final class MultipleAdjust extends Action {
private final List<Adjust> _adjusts = new ArrayList<Adjust>();
private MultipleAdjust() {
}
public List<Adjust> getAdjusts() {
return Collections.unmodifiableList(_adjusts);
}
@Override
protected Action with(final Action other) {
if (other instanceof DontUse) {
throw new OpenGammaRuntimeException("Attempting to mark composite rule as \"Don't Use\"");
}
// other can only be Adjust at this point
_adjusts.add((Adjust) other);
return this;
}
@Override
protected void apply(final ResolutionRule originalRule, final Collection<ResolutionRule> output) {
for (Action adjust : _adjusts) {
adjust.apply(originalRule, output);
}
}
@Override
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof MultipleAdjust)) {
return false;
}
final MultipleAdjust other = (MultipleAdjust) o;
if (_adjusts.size() != other._adjusts.size()) {
return false;
}
for (Action adjust : _adjusts) {
if (!other._adjusts.contains(adjust)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
// Not destined for hash tables
return 0;
}
@Override
public String toString() {
return "Multiple" + _adjusts;
}
}
}