/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.depgraph.impl; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.depgraph.DependencyGraph; import com.opengamma.engine.depgraph.DependencyGraphExplorer; import com.opengamma.engine.depgraph.DependencyNode; import com.opengamma.engine.value.ValueRequirement; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.util.ArgumentChecker; /** * Default engine-side implementation of {@link DependencyGraphExplorer} */ public class DependencyGraphExplorerImpl implements DependencyGraphExplorer { private final DependencyGraph _graph; private volatile Map<ValueSpecification, DependencyNode> _nodesBySpecification; private volatile Set<ComputationTargetSpecification> _allTargets; public DependencyGraphExplorerImpl(DependencyGraph graph) { ArgumentChecker.notNull(graph, "graph"); _graph = graph; } private Map<ValueSpecification, DependencyNode> getNodesBySpecification() { if (_nodesBySpecification == null) { _nodesBySpecification = DependencyGraphImpl.getAllOutputs(_graph); } return _nodesBySpecification; } @Override public String getCalculationConfigurationName() { return _graph.getCalculationConfigurationName(); } @Override public DependencyGraph getWholeGraph() { return _graph; } private static int terminalOutputSubset(final Map<ValueSpecification, Set<ValueRequirement>> allTerminals, final DependencyNode node, final Set<DependencyNode> visited, final Map<ValueSpecification, Set<ValueRequirement>> subsetTerminals) { if (visited.add(node)) { int count = node.getInputCount(); int size = 1; for (int i = 0; i < count; i++) { size += terminalOutputSubset(allTerminals, node.getInputNode(i), visited, subsetTerminals); } count = node.getOutputCount(); for (int i = 0; i < count; i++) { final Set<ValueRequirement> terminals = allTerminals.get(node.getOutputValue(i)); if (terminals != null) { subsetTerminals.put(node.getOutputValue(i), terminals); } } return size; } else { return 0; } } @Override public DependencyGraphExplorer getSubgraphProducing(final ValueSpecification output) { final DependencyNode terminalNode = getNodeProducing(output); if (terminalNode == null) { return null; } final Set<DependencyNode> visited = new HashSet<DependencyNode>(); final Map<ValueSpecification, Set<ValueRequirement>> terminals = new HashMap<ValueSpecification, Set<ValueRequirement>>(); final int nodes = terminalOutputSubset(_graph.getTerminalOutputs(), terminalNode, visited, terminals); return new DependencyGraphExplorerImpl(new DependencyGraphImpl(_graph.getCalculationConfigurationName(), Collections.singleton(terminalNode), nodes, terminals)); } @Override public DependencyNode getNodeProducing(final ValueSpecification output) { return getNodesBySpecification().get(output); } @Override public Map<ValueSpecification, Set<ValueRequirement>> getTerminalOutputs() { return _graph.getTerminalOutputs(); } @Override public Set<ComputationTargetSpecification> getComputationTargets() { Set<ComputationTargetSpecification> targets = _allTargets; if (targets == null) { targets = new HashSet<ComputationTargetSpecification>(); final Iterator<DependencyNode> itr = _graph.nodeIterator(); while (itr.hasNext()) { targets.add(itr.next().getTarget()); } _allTargets = targets; } return targets; } }