Java tutorial
/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.view.cycle; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.apache.commons.lang.ObjectUtils; import com.opengamma.engine.cache.CacheSelectHint; import com.opengamma.engine.cache.ViewComputationCache; import com.opengamma.engine.depgraph.DependencyGraph; import com.opengamma.engine.depgraph.DependencyNode; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.util.ArgumentChecker; /** * Determines which nodes in a graph have changed. A node has 'changed' if and only if its subtree contains a node for which PreviousLiveDataInput != CurrentLiveDataInput. Note that this excludes * changes due to passage of the system clock. */ public class LiveDataDeltaCalculator { private final DependencyGraph _graph; private final ViewComputationCache _cache; private final ViewComputationCache _previousCache; private final Set<DependencyNode> _changedNodes = new HashSet<DependencyNode>(); private final Set<DependencyNode> _unchangedNodes = new HashSet<DependencyNode>(); private boolean _done; // = false /** * For the delta calculation to be meaningful, the caches should be populated with LiveData inputs required to compute the given dependency graph. See {@link DependencyNode#getRequiredLiveData()} * and {@link ViewComputationCache#getValue(ValueSpecification)}. * * @param graph Dependency graph * @param cache Contains CurrentLiveDataInputs (for the given graph) * @param previousCache Contains PreviousLiveDataInputs (for the given graph) */ public LiveDataDeltaCalculator(final DependencyGraph graph, final ViewComputationCache cache, final ViewComputationCache previousCache) { ArgumentChecker.notNull(graph, "Graph"); ArgumentChecker.notNull(cache, "Cache"); ArgumentChecker.notNull(previousCache, "Previous cache"); _graph = graph; _cache = cache; _previousCache = previousCache; } public Set<DependencyNode> getChangedNodes() { if (!_done) { throw new IllegalStateException("Call computeDelta() first"); } return Collections.unmodifiableSet(_changedNodes); } public Set<DependencyNode> getUnchangedNodes() { if (!_done) { throw new IllegalStateException("Call computeDelta() first"); } return Collections.unmodifiableSet(_unchangedNodes); } public void computeDelta() { if (_done) { throw new IllegalStateException("Cannot determine delta twice"); } for (final DependencyNode rootNode : _graph.getRootNodes()) { computeDelta(rootNode); } _done = true; } private boolean computeDelta(final DependencyNode node) { if (_changedNodes.contains(node)) { return true; } if (_unchangedNodes.contains(node)) { return false; } boolean hasChanged = false; Collection<DependencyNode> inputNodes = node.getInputNodes(); if (inputNodes.isEmpty()) { if (node.isMarketDataSourcingFunction()) { // This is a graph leaf, but market data changes may affect the function of the node. for (ValueSpecification liveData : node.getOutputValues()) { // Market data is always in the shared cache final Object oldValue = _previousCache.getValue(liveData, CacheSelectHint.allShared()); final Object newValue = _cache.getValue(liveData, CacheSelectHint.allShared()); if (!ObjectUtils.equals(oldValue, newValue)) { hasChanged = true; break; } } } // Note: an "else" branch here is where we'd support "volatile" functions } else { for (final DependencyNode inputNode : inputNodes) { // if any children changed, this node requires recalculation hasChanged |= computeDelta(inputNode); } } if (hasChanged) { _changedNodes.add(node); } else { _unchangedNodes.add(node); } return hasChanged; } }