Package com.opengamma.engine.function.resolver

Source Code of com.opengamma.engine.function.resolver.ComputationTargetResults

/**
* Copyright (C) 2011 - 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.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Maps;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.ComputationTargetResolver;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.function.CompiledFunctionDefinition;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionCompilationContextAware;
import com.opengamma.engine.target.ComputationTargetResolverUtils;
import com.opengamma.engine.target.ComputationTargetSpecificationResolver;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.PublicAPI;

/**
* Service to interrogate the results available on a computation target.
*/
@PublicAPI
public class ComputationTargetResults implements FunctionCompilationContextAware {

  private static final Logger s_logger = LoggerFactory.getLogger(ComputationTargetResults.class);

  /**
   * The resolution rules to use, in descending priority order.
   */
  private final List<ResolutionRule> _rules;

  /**
   * The compilation context to use for recursive query. Typically this should be
   * the context this service is part of. On construction, that context is cloned
   * so that the service can be removed from the copy. This prevents functions
   * that are defined in terms of the available outputs of others from being caught
   * in an infinite loop of recursive calls.
   */
  private FunctionCompilationContext _context;

  /**
   * Creates a new instance.
   *
   * @param rules the resolution rules to use, not null
   */
  public ComputationTargetResults(final Collection<ResolutionRule> rules) {
    ArgumentChecker.notNull(rules, "rules");
    _rules = new ArrayList<ResolutionRule>(rules);
    Collections.sort(_rules, new Comparator<ResolutionRule>() {

      @Override
      public int compare(final ResolutionRule o1, final ResolutionRule o2) {
        if (o1.getPriority() > o2.getPriority()) {
          return -1;
        } else if (o1.getPriority() < o2.getPriority()) {
          return 1;
        } else {
          return 0;
        }
      }

    });
  }

  @Override
  public void setFunctionCompilationContext(final FunctionCompilationContext context) {
    if (_context == null) {
      _context = context.clone();
      _context.setComputationTargetResults(null);
    }
  }

  /**
   * Gets the list of resolution rules, in descending priority order.
   *
   * @return the rules, not null
   */
  protected List<ResolutionRule> getRules() {
    return _rules;
  }

  /**
   * Gets the function compilation context (lacking this service).
   *
   * @return the context, not null
   */
  protected FunctionCompilationContext getContext() {
    return _context;
  }

  /**
   * Gets the target resolver to use for partial result resolution.
   *
   * @return the target resolver, not null
   */
  protected ComputationTargetResolver.AtVersionCorrection getTargetResolver() {
    return getContext().getComputationTargetResolver();
  }

  /**
   * Gets the specification resolver to use for targets specified by external identifier only.
   *
   * @return the
   */
  protected ComputationTargetSpecificationResolver.AtVersionCorrection getTargetSpecificationResolver() {
    return getContext().getComputationTargetResolver().getSpecificationResolver();
  }

  /**
   * Returns the maximal result sets from all functions on the given target. The results
   * are presented in the descending priority order of the rules that produced them.
   *
   * @param target the target to get results for, not null
   * @return the list of maximal results, not null
   */
  public List<ValueSpecification> getMaximalResults(final ComputationTarget target) {
    final Set<ValueSpecification> result = new LinkedHashSet<ValueSpecification>();
    for (final ResolutionRule rule : getRules()) {
      if (rule.getParameterizedFunction().getFunction().getTargetType().isCompatible(target.getType())) {
        final Set<ValueSpecification> results = rule.getResults(target, getContext());
        if (results != null) {
          result.addAll(results);
        }
      }
    }
    s_logger.info("Maximal results for {} = {}", target, result);
    return new ArrayList<ValueSpecification>(result);
  }

  /**
   * Returns the partially resolved result sets from all functions on the given target.
   * The results are presented in the descending priority order of the rules that produced
   * them.
   * <p>
   * This differs from {@link #getMaximalResults} by following the requirements of any
   * functions that produce non-finite properties on their maximal outputs.
   *
   * @param target the target to get results for, not null
   * @return the list of partially resolved results, not null
   */
  public List<ValueSpecification> getPartialResults(final ComputationTarget target) {
    final Map<ComputationTargetType, ComputationTarget> adjustedTargetCache = new HashMap<ComputationTargetType, ComputationTarget>();
    final Set<ValueSpecification> result = new LinkedHashSet<ValueSpecification>();
    for (final ResolutionRule rule : getRules()) {
      final CompiledFunctionDefinition function = rule.getParameterizedFunction().getFunction();
      if (!function.getTargetType().isCompatible(target.getType())) {
        continue;
      }
      final ComputationTarget adjustedTarget = rule.adjustTarget(adjustedTargetCache, target);
      final Set<ValueSpecification> results;
      try {
        results = rule.getResults(adjustedTarget, getContext());
        if (results == null) {
          continue;
        }
      } catch (final Throwable t) {
        s_logger.warn("Couldn't call getResults on {} - {}", rule, t);
        s_logger.debug("Caught exception", t);
        continue;
      }
      //CSOFF
      resultsLoop:
      //CSON
      for (final ValueSpecification spec : results) {
        if (!spec.getProperties().getProperties().isEmpty()) {
          result.add(spec);
          continue resultsLoop;
        }
        final ValueSpecification resolvedSpec = resolvePartialSpecification(spec, adjustedTarget, function, new HashSet<ValueRequirement>(), adjustedTargetCache, ValueProperties.none());
        if (resolvedSpec != null) {
          result.add(resolvedSpec);
        }
      }
    }
    s_logger.info("Maximal results for {} = {}", target, result);
    return new ArrayList<ValueSpecification>(result);
  }

  /**
   * Attempts partial resolution of a requirement. Requirement chains are followed until a specification is found with finite properties.
   *
   * @param requirement requirement to resolve, not null
   * @param visited requirements visited so far, to detect recursion, not null
   * @param adjustedTargetCache cache of adjusted targets, keyed by the target function type, not null
   * @return the resolved specification, or null if it couldn't be resolved
   */
  protected ValueSpecification resolvePartialRequirement(final ValueRequirement requirement, final Set<ValueRequirement> visited,
      final Map<ComputationTargetType, ComputationTarget> adjustedTargetCache) {
    if (!visited.add(requirement)) {
      s_logger.debug("Recursive request for {}", requirement);
      return null;
    }
    final ComputationTargetSpecification targetSpec = getTargetSpecificationResolver().getTargetSpecification(
        ComputationTargetResolverUtils.simplifyType(requirement.getTargetReference(), getTargetResolver()));
    final ComputationTarget target = getTargetResolver().resolve(targetSpec);
    if (target == null) {
      s_logger.debug("Couldn't resolve target for {}", requirement);
      visited.remove(requirement);
      return null;
    }
    s_logger.debug("Partially resolving {}", requirement);
    for (final ResolutionRule rule : getRules()) {
      final CompiledFunctionDefinition function = rule.getParameterizedFunction().getFunction();
      if (!function.getTargetType().isCompatible(target.getType())) {
        continue;
      }
      final ComputationTarget adjustedTarget = rule.adjustTarget(adjustedTargetCache, target);
      final ValueSpecification result;
      try {
        result = rule.getResult(requirement.getValueName(), adjustedTarget, requirement.getConstraints(), getContext());
        if (result == null) {
          continue;
        }
      } catch (final Throwable t) {
        s_logger.warn("Couldn't call getResult on {} - {}", rule, t);
        s_logger.debug("Caught exception", t);
        continue;
      }
      if (!result.getProperties().getProperties().isEmpty()) {
        s_logger.debug("Partial resolution of {} to {}", requirement, result);
        visited.remove(requirement);
        return result;
      }
      final ValueSpecification resolvedResult = resolvePartialSpecification(result, adjustedTarget, function, visited, adjustedTargetCache, requirement.getConstraints());
      if (resolvedResult != null) {
        s_logger.debug("Partial resolution of {} to {}", requirement, resolvedResult);
        visited.remove(requirement);
        return resolvedResult;
      }
    }
    s_logger.debug("Couldn't resolve {}", requirement);
    visited.remove(requirement);
    return null;
  }

  /**
   * Attempts partial resolution of a non-finite specification produced as part of a function's maximal outputs. Requirement chains are followed until a specification is found with finite properties.
   *
   * @param specification maximal output specification, non-finite properties, not null
   * @param target computation target the function is to operate on, not null
   * @param function function to apply, not null
   * @param visited requirements visited so far, to detect recursion, not null
   * @param adjustedTarget cache of adjusted targets, keyed by the target function type, not null
   * @param constraints requirement constraints, not null
   * @return the partially resolved specification, or null if resolution is not possible
   */
  protected ValueSpecification resolvePartialSpecification(final ValueSpecification specification, final ComputationTarget target, final CompiledFunctionDefinition function,
      final Set<ValueRequirement> visited, final Map<ComputationTargetType, ComputationTarget> adjustedTarget, final ValueProperties constraints) {
    final Set<ValueRequirement> reqs;
    try {
      reqs = function.getRequirements(getContext(), target, new ValueRequirement(specification.getValueName(), specification.getTargetSpecification(), constraints));
      if (reqs == null) {
        return null;
      }
    } catch (final Throwable t) {
      s_logger.warn("Couldn't call getRequirements on {} - {}", function, t);
      s_logger.debug("Caught exception", t);
      return null;
    }
    s_logger.debug("Need partial resolution of {} to continue", reqs);
    final Map<ValueSpecification, ValueRequirement> resolved = Maps.newHashMapWithExpectedSize(reqs.size());
    for (final ValueRequirement req : reqs) {
      // TODO: need to call "simplify type" on requirement
      final ValueSpecification resolvedReq = resolvePartialRequirement(req, visited, adjustedTarget);
      if (resolvedReq == null) {
        return null;
      }
      resolved.put(resolvedReq, req);
    }
    final Set<ValueSpecification> lateResults;
    try {
      lateResults = function.getResults(getContext(), target, resolved);
      if ((lateResults == null) || lateResults.isEmpty()) {
        return null;
      }
    } catch (final Throwable t) {
      s_logger.warn("Couldn't call getResults on {} - {}", function, t);
      s_logger.debug("Caught exception", t);
      return null;
    }
    for (final ValueSpecification lateSpec : lateResults) {
      if (!lateSpec.getProperties().getProperties().isEmpty()) {
        s_logger.debug("Deep resolution of {} to {}", specification, lateSpec);
        return lateSpec;
      }
    }
    return null;
  }

}
TOP

Related Classes of com.opengamma.engine.function.resolver.ComputationTargetResults

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.