/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.function.blacklist; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.function.FunctionParameters; import com.opengamma.engine.value.ValueSpecification; /** * Basic implementation of a blacklist based on a set of indexed rules. */ public class DefaultFunctionBlacklistQuery extends AbstractFunctionBlacklistQuery { private static final Logger s_logger = LoggerFactory.getLogger(DefaultFunctionBlacklistQuery.class); /** * Field used for the pivot in the tree used to index the rules. */ /* package */enum PivotField { FUNCTION_IDENTIFIER(FUNCTION_IDENTIFIER_MASK), FUNCTION_PARAMETERS(FUNCTION_PARAMETERS_MASK), TARGET(TARGET_MASK), INPUTS(INPUTS_MASK), OUTPUTS(OUTPUTS_MASK); private int _mask; private PivotField(final int mask) { _mask = mask; } public int mask() { return _mask; } } private static final int FUNCTION_IDENTIFIER_MASK = 1; private static final int FUNCTION_PARAMETERS_MASK = 2; private static final int TARGET_MASK = 4; private static final int INPUTS_MASK = 8; private static final int OUTPUTS_MASK = 16; private static final int ALL_PIVOT_FIELDS = 31; private static PivotField nextPivotField(final int mask) { if ((mask & FUNCTION_IDENTIFIER_MASK) != 0) { return PivotField.FUNCTION_IDENTIFIER; } else if ((mask & FUNCTION_PARAMETERS_MASK) != 0) { return PivotField.FUNCTION_PARAMETERS; } else if ((mask & TARGET_MASK) != 0) { return PivotField.TARGET; } else if ((mask & INPUTS_MASK) != 0) { return PivotField.INPUTS; } else if ((mask & OUTPUTS_MASK) != 0) { return PivotField.OUTPUTS; } else { throw new IllegalStateException(); } } // TODO: Partial/exact matching of inputs and outputs is not done properly here. We always do an exact match but warn when // a partial match rule is added to the query /* package */abstract static class TreeEntry { private final PivotField _pivot; public TreeEntry(final PivotField pivot) { _pivot = pivot; } protected PivotField getPivot() { return _pivot; } protected abstract boolean isWildcardBlacklisted(String functionIdentifier, FunctionParameters functionParameters); protected abstract boolean isFunctionIdentifierBlacklisted(String functionIdentifier, FunctionParameters functionParameters); protected abstract boolean isFunctionParametersBlacklisted(String functionIdentifier, FunctionParameters functionParameters); public static boolean isBlacklisted(final TreeEntry node, final String functionIdentifier, final FunctionParameters functionParameters) { return (node != null) && node.isBlacklisted(functionIdentifier, functionParameters); } protected boolean isBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters) { if (isWildcardBlacklisted(functionIdentifier, functionParameters)) { return true; } switch (getPivot()) { case FUNCTION_IDENTIFIER: return isFunctionIdentifierBlacklisted(functionIdentifier, functionParameters); case FUNCTION_PARAMETERS: return isFunctionParametersBlacklisted(functionIdentifier, functionParameters); default: return false; } } protected abstract boolean isWildcardBlacklisted(ComputationTargetSpecification target); protected abstract boolean isTargetBlacklisted(ComputationTargetSpecification target); public static boolean isBlacklisted(final TreeEntry node, final ComputationTargetSpecification target) { return (node != null) && node.isBlacklisted(target); } protected boolean isBlacklisted(final ComputationTargetSpecification target) { if (isWildcardBlacklisted(target)) { return true; } if (getPivot() == PivotField.TARGET) { return isTargetBlacklisted(target); } return false; } protected abstract boolean isWildcardBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target); protected abstract boolean isFunctionIdentifierBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target); protected abstract boolean isFunctionParametersBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target); protected abstract boolean isTargetBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target); public static boolean isBlacklisted(final TreeEntry node, final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { return (node != null) && node.isBlacklisted(functionIdentifier, functionParameters, target); } protected boolean isBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { if (isWildcardBlacklisted(functionIdentifier, functionParameters, target)) { return true; } switch (getPivot()) { case FUNCTION_IDENTIFIER: return isFunctionIdentifierBlacklisted(functionIdentifier, functionParameters, target); case FUNCTION_PARAMETERS: return isFunctionParametersBlacklisted(functionIdentifier, functionParameters, target); case TARGET: return isTargetBlacklisted(functionIdentifier, functionParameters, target); default: return false; } } protected abstract boolean isWildcardBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, ValueSpecification[] inputs, ValueSpecification[] outputs); protected abstract boolean isWildcardBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, Collection<ValueSpecification> inputs, Collection<ValueSpecification> outputs); protected abstract boolean isFunctionIdentifierBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, ValueSpecification[] inputs, ValueSpecification[] outputs); protected abstract boolean isFunctionIdentifierBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, Collection<ValueSpecification> inputs, Collection<ValueSpecification> outputs); protected abstract boolean isFunctionParametersBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, ValueSpecification[] inputs, ValueSpecification[] outputs); protected abstract boolean isFunctionParametersBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, Collection<ValueSpecification> inputs, Collection<ValueSpecification> outputs); protected abstract boolean isTargetBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, ValueSpecification[] inputs, ValueSpecification[] outputs); protected abstract boolean isTargetBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, Collection<ValueSpecification> inputs, Collection<ValueSpecification> outputs); protected abstract boolean isInputsBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, ValueSpecification[] inputs, ValueSpecification[] outputs); protected abstract boolean isInputsBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, Collection<ValueSpecification> inputs, Collection<ValueSpecification> outputs); protected abstract boolean isOutputsBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, ValueSpecification[] inputs, ValueSpecification[] outputs); protected abstract boolean isOutputsBlacklisted(String functionIdentifier, FunctionParameters functionParameters, ComputationTargetSpecification target, Collection<ValueSpecification> inputs, Collection<ValueSpecification> outputs); public static boolean isBlacklisted(final TreeEntry node, final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { return (node != null) && node.isBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); } public static boolean isBlacklisted(final TreeEntry node, final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { return (node != null) && node.isBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); } protected boolean isBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { if (isWildcardBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs)) { return true; } switch (getPivot()) { case FUNCTION_IDENTIFIER: return isFunctionIdentifierBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); case FUNCTION_PARAMETERS: return isFunctionParametersBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); case TARGET: return isTargetBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); case INPUTS: return isInputsBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); case OUTPUTS: return isOutputsBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); default: throw new IllegalStateException(); } } protected boolean isBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { if (isWildcardBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs)) { return true; } switch (getPivot()) { case FUNCTION_IDENTIFIER: return isFunctionIdentifierBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); case FUNCTION_PARAMETERS: return isFunctionParametersBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); case TARGET: return isTargetBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); case INPUTS: return isInputsBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); case OUTPUTS: return isOutputsBlacklisted(functionIdentifier, functionParameters, target, inputs, outputs); default: throw new IllegalStateException(); } } protected abstract void addEntry(FunctionBlacklistRule rule, Object key, int unpivoted); protected abstract void addWildcard(FunctionBlacklistRule rule, int unpivoted); public void add(final FunctionBlacklistRule rule, final int unpivoted) { assert (unpivoted & getPivot().mask()) != 0; switch (getPivot()) { case FUNCTION_IDENTIFIER: if (rule.getFunctionIdentifier() != null) { addEntry(rule, rule.getFunctionIdentifier(), unpivoted ^ FUNCTION_IDENTIFIER_MASK); } else { addWildcard(rule, unpivoted ^ FUNCTION_IDENTIFIER_MASK); } break; case FUNCTION_PARAMETERS: if (rule.getFunctionParameters() != null) { addEntry(rule, rule.getFunctionParameters(), unpivoted ^ FUNCTION_PARAMETERS_MASK); } else { addWildcard(rule, unpivoted ^ FUNCTION_PARAMETERS_MASK); } break; case TARGET: if (rule.getTarget() != null) { addEntry(rule, rule.getTarget(), unpivoted ^ TARGET_MASK); } else { addWildcard(rule, unpivoted ^ TARGET_MASK); } break; case INPUTS: if (rule.getInputs() != null) { addEntry(rule, rule.getInputs(), unpivoted ^ INPUTS_MASK); } else { addWildcard(rule, unpivoted ^ INPUTS_MASK); } break; case OUTPUTS: if (rule.getOutputs() != null) { addEntry(rule, rule.getOutputs(), unpivoted ^ OUTPUTS_MASK); } else { addWildcard(rule, unpivoted ^ OUTPUTS_MASK); } break; default: throw new IllegalStateException(); } } protected abstract boolean removeEntry(FunctionBlacklistRule rule, Object key); protected abstract boolean removeWildcard(FunctionBlacklistRule rule); /** * Removes the rule from the tree. * * @param rule the rule to remove * @return true if the tree is non-empty, false if the tree fragment is empty after the removal */ public boolean remove(final FunctionBlacklistRule rule) { switch (getPivot()) { case FUNCTION_IDENTIFIER: if (rule.getFunctionIdentifier() != null) { return removeEntry(rule, rule.getFunctionIdentifier()); } else { return removeWildcard(rule); } case FUNCTION_PARAMETERS: if (rule.getFunctionParameters() != null) { return removeEntry(rule, rule.getFunctionParameters()); } else { return removeWildcard(rule); } case TARGET: if (rule.getTarget() != null) { return removeEntry(rule, rule.getTarget()); } else { return removeWildcard(rule); } case INPUTS: if (rule.getInputs() != null) { return removeEntry(rule, rule.getInputs()); } else { return removeWildcard(rule); } case OUTPUTS: if (rule.getOutputs() != null) { return removeEntry(rule, rule.getOutputs()); } else { return removeWildcard(rule); } default: throw new IllegalStateException(); } } } /* package */static class MidTreeEntry extends TreeEntry { private volatile TreeEntry _wildcard; private volatile Map<Object, TreeEntry> _values; public MidTreeEntry(final PivotField pivot) { super(pivot); } @Override protected boolean isWildcardBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters) { return isBlacklisted(_wildcard, functionIdentifier, functionParameters); } @Override protected boolean isFunctionIdentifierBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(functionIdentifier), functionIdentifier, functionParameters); } @Override protected boolean isFunctionParametersBlacklisted(String functionIdentifier, final FunctionParameters functionParameters) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(functionParameters), functionIdentifier, functionParameters); } @Override protected boolean isWildcardBlacklisted(final ComputationTargetSpecification target) { return isBlacklisted(_wildcard, target); } @Override protected boolean isTargetBlacklisted(final ComputationTargetSpecification target) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(target), target); } @Override protected boolean isWildcardBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { return isBlacklisted(_wildcard, functionIdentifier, functionParameters, target); } @Override protected boolean isFunctionIdentifierBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(functionIdentifier), functionIdentifier, functionParameters, target); } @Override protected boolean isFunctionParametersBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(functionParameters), functionIdentifier, functionParameters, target); } @Override protected boolean isTargetBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(target), functionIdentifier, functionParameters, target); } @Override protected boolean isWildcardBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { return isBlacklisted(_wildcard, functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isWildcardBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { return isBlacklisted(_wildcard, functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isFunctionIdentifierBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(functionIdentifier), functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isFunctionIdentifierBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(functionIdentifier), functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isFunctionParametersBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(functionParameters), functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isFunctionParametersBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(functionParameters), functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isTargetBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(target), functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isTargetBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(target), functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isInputsBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(inputs), functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isInputsBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(inputs), functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isOutputsBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(outputs), functionIdentifier, functionParameters, target, inputs, outputs); } @Override protected boolean isOutputsBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Map<Object, TreeEntry> values = _values; return (values != null) && isBlacklisted(values.get(outputs), functionIdentifier, functionParameters, target, inputs, outputs); } private TreeEntry createTreeEntry(final int unpivoted) { final PivotField pivot = nextPivotField(unpivoted); if (unpivoted == pivot.mask()) { return new LeafTreeEntry(pivot); } else { return new MidTreeEntry(pivot); } } @Override protected void addEntry(final FunctionBlacklistRule rule, final Object key, final int unpivoted) { Map<Object, TreeEntry> values = _values; TreeEntry next; if (values == null) { next = createTreeEntry(unpivoted); _values = Collections.singletonMap(key, next); } else { next = values.get(key); if (next == null) { next = createTreeEntry(unpivoted); values = new HashMap<Object, TreeEntry>(values); values.put(key, next); _values = values; } } next.add(rule, unpivoted); } @Override protected void addWildcard(final FunctionBlacklistRule rule, final int unpivoted) { TreeEntry wildcard = _wildcard; if (wildcard == null) { wildcard = createTreeEntry(unpivoted); _wildcard = wildcard; } wildcard.add(rule, unpivoted); } @Override protected boolean removeEntry(final FunctionBlacklistRule rule, final Object key) { Map<Object, TreeEntry> values = _values; if (values != null) { TreeEntry next = values.get(key); if (next != null) { if (next.remove(rule)) { return true; } else { values = new HashMap<Object, TreeEntry>(values); values.remove(key); _values = values; return (_wildcard != null) || !values.isEmpty(); } } else { throw new IllegalStateException("Rule " + rule + " not in the collection"); } } else { throw new IllegalStateException("Rule " + rule + " not in the collection"); } } @Override protected boolean removeWildcard(final FunctionBlacklistRule rule) { final TreeEntry wildcard = _wildcard; if (wildcard != null) { if (wildcard.remove(rule)) { return true; } else { _wildcard = null; final Map<Object, TreeEntry> values = _values; return (values != null) && !values.isEmpty(); } } else { throw new IllegalStateException("Rule " + rule + " not in the collection"); } } } /* package */static class LeafTreeEntry extends TreeEntry { private volatile int _wildcard; private volatile Set<Object> _values; public LeafTreeEntry(final PivotField pivot) { super(pivot); } @Override protected boolean isWildcardBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters) { return _wildcard > 0; } @Override protected boolean isFunctionIdentifierBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters) { final Set<Object> values = _values; return (values != null) && values.contains(functionIdentifier); } @Override protected boolean isFunctionParametersBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters) { final Set<Object> values = _values; return (values != null) && values.contains(functionParameters); } @Override protected boolean isWildcardBlacklisted(final ComputationTargetSpecification target) { return _wildcard > 0; } @Override protected boolean isTargetBlacklisted(final ComputationTargetSpecification target) { final Set<Object> values = _values; return (values != null) && values.contains(target); } @Override protected boolean isWildcardBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { return _wildcard > 0; } @Override protected boolean isFunctionIdentifierBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { final Set<Object> values = _values; return (values != null) && values.contains(functionIdentifier); } @Override protected boolean isFunctionParametersBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { final Set<Object> values = _values; return (values != null) && values.contains(functionParameters); } @Override protected boolean isTargetBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { final Set<Object> values = _values; return (values != null) && values.contains(target); } @Override protected boolean isWildcardBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { return _wildcard > 0; } @Override protected boolean isWildcardBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { return _wildcard > 0; } @Override protected boolean isFunctionIdentifierBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Set<Object> values = _values; return (values != null) && values.contains(functionIdentifier); } @Override protected boolean isFunctionIdentifierBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Set<Object> values = _values; return (values != null) && values.contains(functionIdentifier); } @Override protected boolean isFunctionParametersBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Set<Object> values = _values; return (values != null) && values.contains(functionParameters); } @Override protected boolean isFunctionParametersBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Set<Object> values = _values; return (values != null) && values.contains(functionParameters); } @Override protected boolean isTargetBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Set<Object> values = _values; return (values != null) && values.contains(target); } @Override protected boolean isTargetBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Set<Object> values = _values; return (values != null) && values.contains(target); } @Override @SuppressWarnings("unchecked") protected boolean isInputsBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Set<Object> values = _values; if (values == null) { return false; } for (Object value : values) { final Collection<ValueSpecification> valueCollection = (Collection<ValueSpecification>) value; if (valueCollection.size() == inputs.length) { boolean match = true; for (ValueSpecification input : inputs) { if (!((Collection<ValueSpecification>) value).contains(input)) { match = false; break; } } if (match) { return true; } } } return false; } @Override protected boolean isInputsBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Set<Object> values = _values; return (values != null) && values.contains(inputs); } @Override @SuppressWarnings("unchecked") protected boolean isOutputsBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { final Set<Object> values = _values; if (values == null) { return false; } for (Object value : values) { final Collection<ValueSpecification> valueCollection = (Collection<ValueSpecification>) value; if (valueCollection.size() == outputs.length) { boolean match = true; for (ValueSpecification output : outputs) { if (!((Collection<ValueSpecification>) value).contains(output)) { match = false; break; } } if (match) { return true; } } } return false; } @Override protected boolean isOutputsBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { final Set<Object> values = _values; return (values != null) && values.contains(outputs); } @Override protected void addEntry(final FunctionBlacklistRule rule, final Object key, final int unpivoted) { Set<Object> values = _values; if (values == null) { values = Collections.singleton(key); _values = values; } else { values = new HashSet<Object>(values); values.add(key); _values = values; } } @Override protected void addWildcard(final FunctionBlacklistRule rule, final int unpivoted) { _wildcard++; } @Override protected boolean removeEntry(final FunctionBlacklistRule rule, final Object key) { Set<Object> values = _values; if (values != null) { values = new HashSet<Object>(values); if (values.remove(key)) { _values = values; return (_wildcard > 0) || !values.isEmpty(); } else { throw new IllegalStateException("Rule " + rule + " not in the collection"); } } else { throw new IllegalStateException("Rule " + rule + " not in the collection"); } } @Override protected boolean removeWildcard(final FunctionBlacklistRule rule) { final int wildcard = _wildcard; if (wildcard > 0) { _wildcard = wildcard - 1; final Set<Object> values = _values; return (wildcard > 1) || ((values != null) && !values.isEmpty()); } else { throw new IllegalStateException("Rule " + rule + " not in the collection"); } } } private static final class Listener extends AbstractFunctionBlacklistRuleListener { private final WeakReference<DefaultFunctionBlacklistQuery> _ref; public Listener(final FunctionBlacklist blacklist, final DefaultFunctionBlacklistQuery ref) { super(blacklist); _ref = new WeakReference<DefaultFunctionBlacklistQuery>(ref); } @Override protected void init() { super.init(); getBlacklist().addRuleListener(this); refresh(); } private DefaultFunctionBlacklistQuery getReference() { final DefaultFunctionBlacklistQuery ref = _ref.get(); if (ref == null) { getBlacklist().removeRuleListener(this); } return ref; } @Override protected void replaceRules(final Collection<FunctionBlacklistRule> rules) { final DefaultFunctionBlacklistQuery ref = getReference(); if (ref != null) { ref.replaceRules(rules); } } @Override protected void addRule(final FunctionBlacklistRule rule) { final DefaultFunctionBlacklistQuery ref = getReference(); if (ref != null) { ref.addRule(rule); } } @Override protected void addRules(final Collection<FunctionBlacklistRule> rules) { final DefaultFunctionBlacklistQuery ref = getReference(); if (ref != null) { ref.addRules(rules); } } @Override protected void removeRule(final FunctionBlacklistRule rule) { final DefaultFunctionBlacklistQuery ref = getReference(); if (ref != null) { ref.removeRule(rule); } } @Override protected void removeRules(final Collection<FunctionBlacklistRule> rules) { final DefaultFunctionBlacklistQuery ref = getReference(); if (ref != null) { ref.removeRules(rules); } } } private final Set<FunctionBlacklistRule> _rules = new HashSet<FunctionBlacklistRule>(); private volatile TreeEntry _root; public DefaultFunctionBlacklistQuery(final FunctionBlacklist blacklist) { (new Listener(blacklist, this)).init(); } @Override public boolean isEmpty() { return _root == null; } @Override public boolean isBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters) { return TreeEntry.isBlacklisted(_root, functionIdentifier, functionParameters); } @Override public boolean isBlacklisted(final ComputationTargetSpecification target) { return TreeEntry.isBlacklisted(_root, target); } @Override public boolean isBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target) { return TreeEntry.isBlacklisted(_root, functionIdentifier, functionParameters, target); } @Override public boolean isBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final ValueSpecification[] inputs, final ValueSpecification[] outputs) { return TreeEntry.isBlacklisted(_root, functionIdentifier, functionParameters, target, inputs, outputs); } @Override public boolean isBlacklisted(final String functionIdentifier, final FunctionParameters functionParameters, final ComputationTargetSpecification target, final Collection<ValueSpecification> inputs, final Collection<ValueSpecification> outputs) { return TreeEntry.isBlacklisted(_root, functionIdentifier, functionParameters, target, inputs, outputs); } protected synchronized void addRule(final FunctionBlacklistRule rule) { if (_rules.add(rule)) { addRuleImpl(rule); } } protected synchronized void addRules(final Collection<FunctionBlacklistRule> rules) { for (FunctionBlacklistRule rule : rules) { if (_rules.add(rule)) { addRuleImpl(rule); } } } protected synchronized void removeRule(final FunctionBlacklistRule rule) { if (_rules.remove(rule)) { removeRuleImpl(rule); } } protected synchronized void removeRules(final Collection<FunctionBlacklistRule> rules) { for (FunctionBlacklistRule rule : rules) { if (_rules.remove(rule)) { removeRuleImpl(rule); } } } protected synchronized void replaceRules(final Collection<FunctionBlacklistRule> rules) { _rules.clear(); _root = null; for (FunctionBlacklistRule rule : rules) { if (_rules.add(rule)) { addRuleImpl(rule); } } } /** * Adds a rule to the collection used. The content of the rule is copied - no reference to the rule is retained. The caller must hold the monitor. * * @param rule the rule to add, not null */ private void addRuleImpl(final FunctionBlacklistRule rule) { if (((rule.getInputs() != null) && !rule.isInputsExactMatch()) || ((rule.getOutputs() != null) && !rule.isOutputsExactMatch())) { s_logger.warn("Rule {} specifies partial input/output match", rule); } if (_root == null) { _root = new MidTreeEntry(PivotField.FUNCTION_IDENTIFIER); } _root.add(rule, ALL_PIVOT_FIELDS); } // TODO: Sometimes might want to reorder the pivots. Would we want "cheapest" pivot first, the one with the most choices or the one with the fewest choices? The aim is // to get a "FALSE" as quickly and cheaply as possible as that is the typical case. /** * Removes a rule from the collection used. The rule must exist in the collection. The caller must hold the monitor. * * @param rule the rule to remove, not null */ private void removeRuleImpl(final FunctionBlacklistRule rule) { if (!_root.remove(rule)) { _root = null; } } }