/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.core.change.ChangeManager; import com.opengamma.core.change.PassthroughChangeManager; import com.opengamma.core.position.PositionSource; import com.opengamma.core.security.SecuritySource; import com.opengamma.engine.target.ComputationTargetResolverUtils; import com.opengamma.engine.target.ComputationTargetSpecificationResolver; import com.opengamma.engine.target.ComputationTargetType; import com.opengamma.engine.target.ComputationTargetTypeMap; import com.opengamma.engine.target.ComputationTargetTypeProvider; import com.opengamma.engine.target.ComputationTargetTypeVisitor; import com.opengamma.engine.target.DefaultComputationTargetSpecificationResolver; import com.opengamma.engine.target.PrimitiveComputationTargetType; import com.opengamma.engine.target.lazy.LazyResolveContext; import com.opengamma.engine.target.lazy.LazyResolver; import com.opengamma.engine.target.resolver.ChainedResolver; import com.opengamma.engine.target.resolver.IdentifierResolver; import com.opengamma.engine.target.resolver.ObjectResolver; import com.opengamma.engine.target.resolver.PositionSourceResolver; import com.opengamma.engine.target.resolver.SecuritySourceResolver; import com.opengamma.id.UniqueId; import com.opengamma.id.UniqueIdentifiable; import com.opengamma.id.VersionCorrection; import com.opengamma.util.ArgumentChecker; /** * A computation target resolver implementation that resolves using a security and position source. * <p> * This is the standard implementation that resolves from a target specification to a real target. It provides results using a security and position source. */ public class DefaultComputationTargetResolver implements ComputationTargetResolver, LazyResolver, ComputationTargetTypeProvider { // [PLAT-444]: move to com.opengamma.engine.target /** Logger. */ private static final Logger s_logger = LoggerFactory.getLogger(DefaultComputationTargetResolver.class); /** * The security source. */ private final SecuritySource _securitySource; /** * The position source. */ private final PositionSource _positionSource; /** * The per-type resolvers. */ private final ComputationTargetTypeMap<ObjectResolver<?>> _resolvers = new ComputationTargetTypeMap<ObjectResolver<?>>(ChainedResolver.CREATE); /** * The type-reductions used. */ private final ComputationTargetTypeMap<ComputationTargetType> _baseTypes = new ComputationTargetTypeMap<ComputationTargetType>(); private final DefaultComputationTargetSpecificationResolver _specificationResolver = new DefaultComputationTargetSpecificationResolver(); private LazyResolveContext _lazyResolveContext; /** * Creates a resolver without access to a security source or a position source. This will only be able to resolve PRIMITIVE computation target types. */ public DefaultComputationTargetResolver() { this(null, null); } /** * Creates a resolver using a security source only. This will not be able to resolve POSITION and PORTFOLIO_NODE computation target types. * * @param securitySource the security source, null prevents some targets from resolving */ public DefaultComputationTargetResolver(final SecuritySource securitySource) { this(securitySource, null); } /** * Creates a resolver using a security and position source This will be able to resolve any type of computation target. * * @param securitySource the security source, null prevents some targets from resolving * @param positionSource the position source, null prevents some targets from resolving */ public DefaultComputationTargetResolver(final SecuritySource securitySource, final PositionSource positionSource) { _securitySource = securitySource; if (securitySource != null) { addResolver(ComputationTargetType.SECURITY, new SecuritySourceResolver(securitySource)); } _positionSource = positionSource; if (positionSource != null) { final PositionSourceResolver resolver = new PositionSourceResolver(positionSource); addResolver(ComputationTargetType.PORTFOLIO, new LazyResolver.LazyPortfolioResolver(this, resolver.portfolio())); addResolver(ComputationTargetType.PORTFOLIO_NODE, new LazyResolver.LazyPortfolioNodeResolver(this, resolver.portfolioNode())); addResolver(ComputationTargetType.POSITION, new LazyResolver.LazyPositionResolver(this, resolver.position())); addResolver(ComputationTargetType.TRADE, new LazyResolver.LazyTradeResolver(this, resolver.trade())); } addResolver(ComputationTargetType.CURRENCY); addResolver(ComputationTargetType.PRIMITIVE); addResolver(ComputationTargetType.UNORDERED_CURRENCY_PAIR); addResolver(ComputationTargetType.CREDIT_CURVE_IDENTIFIER); _lazyResolveContext = new LazyResolveContext(securitySource, null); } /** * Adds a resolver for use with targets of the given type. If the resolver also implements the {@link IdentifierResolver} interface then it will be registered for target specification resolution as * well as object resolution. * * @param <T> the target type * @param type the type(s) to use this resolver for, never null * @param resolver the resolver to use, not null */ public <T extends UniqueIdentifiable> void addResolver(final ComputationTargetType type, final ObjectResolver<T> resolver) { _resolvers.put(type, resolver, _resolvers.getFoldFunction()); _baseTypes.put(type, type); if (resolver instanceof IdentifierResolver) { _specificationResolver.addResolver(type, (IdentifierResolver) resolver); } } /** * Registers a primitive type with the resolver using the primitive type's default resolution strategy to convert {@link UniqueId} instances to the target object. * * @param type the primitive type to resolve, never null */ public void addResolver(final PrimitiveComputationTargetType<?> type) { addResolver(type, type); } @Override public void setLazyResolveContext(final LazyResolveContext context) { ArgumentChecker.notNull(context, "context"); _lazyResolveContext = context; } @Override public LazyResolveContext getLazyResolveContext() { return _lazyResolveContext; } /** * Gets the security source which provides access to the securities. * * @return the security source, may be null */ @Override public SecuritySource getSecuritySource() { return _securitySource; } /** * Gets the position source which provides access to the positions. * * @return the position source, may be null */ protected PositionSource getPositionSource() { return _positionSource; } /** * Resolves the specification using the security and position sources. * <p> * The key method of this class, implementing {@code ComputationTargetResolver}. It examines the specification and resolves the most appropriate target. * * @param specification the specification to resolve, not null * @param versionCorrection the version/correction timestamp to use for the resolution, not null * @return the resolved target, null if not found */ @Override public ComputationTarget resolve(final ComputationTargetSpecification specification, final VersionCorrection versionCorrection) { final ComputationTargetType type = specification.getType(); if (ComputationTargetType.NULL == type) { return ComputationTarget.NULL; } else { final ObjectResolver<?> resolver = _resolvers.get(type); if (resolver != null) { final UniqueIdentifiable resolved = resolver.resolveObject(specification.getUniqueId(), versionCorrection); if (resolved != null) { return ComputationTargetResolverUtils.createResolvedTarget(specification, resolved); } else { s_logger.info("Unable to resolve {}", specification); return null; } } else { throw new OpenGammaRuntimeException("Unhandled computation target type " + specification.getType()); } } } @Override public ObjectResolver<?> getResolver(final ComputationTargetSpecification specification) { final ComputationTargetType type = specification.getType(); if (ComputationTargetType.NULL == type) { return (ObjectResolver<?>) ComputationTargetType.NULL; } else { return _resolvers.get(type); } } private static final ComputationTargetTypeVisitor<ComputationTargetTypeMap<ComputationTargetType>, ComputationTargetType> s_simplifyType = new ComputationTargetTypeVisitor<ComputationTargetTypeMap<ComputationTargetType>, ComputationTargetType>() { @Override public ComputationTargetType visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final ComputationTargetTypeMap<ComputationTargetType> data) { final ComputationTargetType[] result = new ComputationTargetType[types.size()]; int i = 0; boolean changed = false; for (final ComputationTargetType type : types) { final ComputationTargetType newType = type.accept(this, data); if ((newType != null) && (newType != type)) { result[i++] = newType; changed = true; } else { result[i++] = type; } } return changed ? ComputationTargetType.multiple(result) : null; } @Override public ComputationTargetType visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final ComputationTargetTypeMap<ComputationTargetType> data) { final int length = types.size(); for (int i = 0; i < length; i++) { ComputationTargetType type = types.get(i); ComputationTargetType newType = type.accept(this, data); if ((newType != null) && (newType != type)) { ComputationTargetType result; if (i > 0) { result = types.get(0); for (int j = 1; j < i; j++) { result = result.containing(types.get(j)); } result = result.containing(newType); } else { result = newType; } for (int j = i + 1; j < length; j++) { type = types.get(j); newType = type.accept(this, data); result = result.containing((newType == null) ? type : newType); } return result; } } return null; } @Override public ComputationTargetType visitNullComputationTargetType(final ComputationTargetTypeMap<ComputationTargetType> data) { return null; } @Override public ComputationTargetType visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final ComputationTargetTypeMap<ComputationTargetType> data) { return data.get(type); } }; @Override public ComputationTargetType simplifyType(final ComputationTargetType type) { final ComputationTargetType newType = type.accept(s_simplifyType, _baseTypes); if (newType != null) { return newType; } else { return type; } } @Override public ComputationTargetSpecificationResolver getSpecificationResolver() { return _specificationResolver; } @Override public ComputationTargetResolver.AtVersionCorrection atVersionCorrection(final VersionCorrection versionCorrection) { final ComputationTargetSpecificationResolver.AtVersionCorrection specificationResolver = getSpecificationResolver().atVersionCorrection(versionCorrection); return new ComputationTargetResolver.AtVersionCorrection() { @Override public ComputationTargetType simplifyType(final ComputationTargetType type) { return DefaultComputationTargetResolver.this.simplifyType(type); } @Override public ComputationTarget resolve(final ComputationTargetSpecification specification) { return DefaultComputationTargetResolver.this.resolve(specification, versionCorrection); } @Override public ObjectResolver<?> getResolver(final ComputationTargetSpecification specification) { return DefaultComputationTargetResolver.this.getResolver(specification); } @Override public ComputationTargetSpecificationResolver.AtVersionCorrection getSpecificationResolver() { return specificationResolver; } @Override public VersionCorrection getVersionCorrection() { return versionCorrection; } }; } @Override public ChangeManager changeManager() { return new PassthroughChangeManager(_resolvers.values()); } /** * Returns a string suitable for debugging. * * @return the string, not null */ @Override public String toString() { return getClass().getSimpleName() + "[securitySource=" + getSecuritySource() + ",positionSource=" + getPositionSource() + "]"; } // ComputationTargetTypeProvider @Override public Collection<ComputationTargetType> getSimpleTypes() { final Set<ComputationTargetType> types = new HashSet<ComputationTargetType>(); for (final ComputationTargetType baseType : _baseTypes.values()) { types.add(baseType); } return types; } @Override public Collection<ComputationTargetType> getAdditionalTypes() { return Collections.emptySet(); } @Override public Collection<ComputationTargetType> getAllTypes() { return getSimpleTypes(); } }