/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.depgraph.ambiguity; import java.io.PrintStream; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.Instant; import com.opengamma.core.position.PortfolioNode; import com.opengamma.core.position.Position; import com.opengamma.core.position.Trade; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.function.FunctionCompilationContext; import com.opengamma.engine.function.exclusion.FunctionExclusionGroups; import com.opengamma.engine.function.resolver.FunctionResolver; import com.opengamma.engine.marketdata.availability.DefaultMarketDataAvailabilityProvider; import com.opengamma.engine.marketdata.availability.MarketDataAvailabilityProvider; import com.opengamma.engine.marketdata.availability.OptimisticMarketDataAvailabilityFilter; import com.opengamma.engine.target.ComputationTargetType; import com.opengamma.engine.value.ValueProperties; import com.opengamma.engine.value.ValueRequirement; import com.opengamma.engine.view.ViewCalculationConfiguration; import com.opengamma.engine.view.ViewDefinition; import com.opengamma.id.VersionCorrection; import com.opengamma.util.PoolExecutor; import com.opengamma.util.PoolExecutor.CompletionListener; import com.opengamma.util.tuple.Pair; /** * Base class for an integration test that can scan view definitions for ambiguities. */ public abstract class ViewDefinitionAmbiguityTest { private static final Logger s_logger = LoggerFactory.getLogger(ViewDefinitionAmbiguityTest.class); protected MarketDataAvailabilityProvider createMarketDataAvailabilityProvider() { return new OptimisticMarketDataAvailabilityFilter().withProvider(new DefaultMarketDataAvailabilityProvider()); } protected FunctionCompilationContext createFunctionCompilationContext() { return new FunctionCompilationContext(); } protected abstract FunctionResolver createFunctionResolver(); protected FunctionExclusionGroups createFunctionExclusionGroups() { return null; } protected AmbiguityCheckerContext createAmbiguityCheckerContext() { return new AmbiguityCheckerContext(createMarketDataAvailabilityProvider(), createFunctionCompilationContext(), createFunctionResolver(), createFunctionExclusionGroups()); } protected void configureChecker(final SimpleRequirementAmbiguityChecker checker) { checker.setGreedyCaching(true); checker.setSharedCaching(true); } protected void report(final FullRequirementResolution resolution, final PrintStream out) { new FullRequirementResolutionPrinter(out).print(resolution); } protected void directAmbiguity(final FullRequirementResolution resolution) { synchronized (System.err) { System.err.println("Got ambiguity on " + resolution.getRequirement()); report(resolution, System.err); } } protected void deepAmbiguity(final FullRequirementResolution resolution) { synchronized (System.err) { System.err.println("Got deep ambiguity on " + resolution.getRequirement()); report(resolution, System.err); } } protected void resolved(final FullRequirementResolution resolution) { if (resolution.isAmbiguous()) { directAmbiguity(resolution); } else if (resolution.isDeeplyAmbiguous()) { deepAmbiguity(resolution); } else if (resolution.isResolved()) { unresolved(resolution.getRequirement()); } else { s_logger.debug("Resolved {} to {}", resolution.getRequirement(), resolution); } } protected void unresolved(final ValueRequirement requirement) { s_logger.debug("Couldn't resolve {}", requirement); } protected void check(final PoolExecutor.Service<FullRequirementResolution> executor, final RequirementAmbiguityChecker checker, final ValueRequirement requirement) { executor.execute(new Callable<FullRequirementResolution>() { @Override public FullRequirementResolution call() throws Exception { return checker.resolve(requirement); } }); } protected void checkRequirements(final PoolExecutor.Service<FullRequirementResolution> executor, final RequirementAmbiguityChecker checker, final Set<Pair<String, ValueProperties>> requirements, final Trade trade) { for (Pair<String, ValueProperties> requirement : requirements) { check(executor, checker, new ValueRequirement(requirement.getFirst(), new ComputationTargetSpecification(ComputationTargetType.TRADE, trade.getUniqueId()), requirement.getSecond())); } } protected void checkRequirements(final PoolExecutor.Service<FullRequirementResolution> executor, final RequirementAmbiguityChecker checker, final Map<String, Set<Pair<String, ValueProperties>>> requirements, final PortfolioNode node, final Position position, final Set<Pair<String, ValueProperties>> aggregate) { Set<Pair<String, ValueProperties>> securityRequirements = requirements.get(position.getSecurity().getSecurityType()); if (securityRequirements != null) { for (Trade trade : position.getTrades()) { checkRequirements(executor, checker, securityRequirements, trade); } final ComputationTargetSpecification nodeSpec = new ComputationTargetSpecification(ComputationTargetType.PORTFOLIO_NODE, node.getUniqueId()); for (Pair<String, ValueProperties> requirement : securityRequirements) { check(executor, checker, new ValueRequirement(requirement.getFirst(), nodeSpec.containing(ComputationTargetType.POSITION, position.getUniqueId()), requirement.getSecond())); } aggregate.addAll(securityRequirements); } } protected void checkRequirements(final PoolExecutor.Service<FullRequirementResolution> executor, final RequirementAmbiguityChecker checker, final Map<String, Set<Pair<String, ValueProperties>>> requirements, final PortfolioNode node, final Set<Pair<String, ValueProperties>> aggregate) { for (PortfolioNode childNode : node.getChildNodes()) { checkRequirements(executor, checker, requirements, childNode, aggregate); } for (Position position : node.getPositions()) { checkRequirements(executor, checker, requirements, node, position, aggregate); } for (Pair<String, ValueProperties> requirement : aggregate) { check(executor, checker, new ValueRequirement(requirement.getFirst(), new ComputationTargetSpecification(ComputationTargetType.PORTFOLIO_NODE, node.getUniqueId()), requirement.getSecond())); } } public void runAmbiguityTest(final ViewDefinition view) throws InterruptedException { final PoolExecutor executor = new PoolExecutor(Runtime.getRuntime().availableProcessors(), "AmbiguityCheck"); try { final PoolExecutor.Service<FullRequirementResolution> service = executor.createService(new CompletionListener<FullRequirementResolution>() { @Override public void success(final FullRequirementResolution result) { try { resolved(result); } catch (Throwable t) { failure(t); } } @Override public void failure(final Throwable error) { s_logger.error("Internal failure", error); } }); final AmbiguityCheckerContext context = createAmbiguityCheckerContext(); long tStart = System.nanoTime(); for (ViewCalculationConfiguration calcConfig : view.getAllCalculationConfigurations()) { s_logger.info("Testing {}.{}", view.getName(), calcConfig.getName()); final SimpleRequirementAmbiguityChecker checker = new SimpleRequirementAmbiguityChecker(context, Instant.now(), VersionCorrection.LATEST, calcConfig); final Set<Pair<String, ValueProperties>> aggregate = new HashSet<Pair<String, ValueProperties>>(); checkRequirements(service, checker, calcConfig.getPortfolioRequirementsBySecurityType(), checker.getCompilationContext().getPortfolio().getRootNode(), aggregate); } service.join(); s_logger.info("View {} tested in {}s", view.getName(), (double) (System.nanoTime() - tStart) / 1e9); } finally { executor.asService().shutdown(); } } }