/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.collect.id; import java.util.function.Function; import com.google.common.reflect.TypeToken; /** * A resolver that can provide the target when resolving links. * <p> * A {@link Link} provides loose coupling between different parts of the object model. * When the target of a link is needed, it is resolved by passing in a link resolver. * <p> * Link resolution will typically be implemented to access an underlying data store. * If the link specifies an identifier that is not resolvable, or the declared target * type is incorrect, an exception is thrown. */ public interface LinkResolver { /** * Resolves the supplied link, returning the realized target of the link. * <p> * The implementation of this interface may perform any thread-safe action to obtain * the link target. Typically this will involve accessing an underlying data store. * If the link cannot be resolved then a {@code LinkResolutionException} will be thrown. * <p> * The type is expressed as a standard {@link Class} object. * * @param <T> the type of the target of the link * @param identifier the identifier to be resolved * @param targetType the target type of the link * @return the resolved target of the link * @throws LinkResolutionException if the link cannot be resolved */ public default <T extends IdentifiableBean> T resolve(StandardId identifier, Class<T> targetType) { return resolve(identifier, TypeToken.of(targetType)); } /** * Resolves the supplied link, returning the realized target of the link. * <p> * The implementation of this interface may perform any thread-safe action to obtain * the link target. Typically this will involve accessing an underlying data store. * If the link cannot be resolved then a {@code LinkResolutionException} will be thrown. * <p> * The type is expressed as a {@link TypeToken}, which allows types like * {@code Trade<Swap>} to be expressed: * <p> * <pre>{@code * new TypeToken<Trade<Swap>>() {}; * }</pre> * * @param <T> the type of the target of the link * @param identifier the identifier to be resolved * @param targetType the target type of the link * @return the resolved target of the link * @throws LinkResolutionException if the link cannot be resolved */ public abstract <T extends IdentifiableBean> T resolve(StandardId identifier, TypeToken<T> targetType); //------------------------------------------------------------------------- /** * Resolves all the links within one property of a bean. * <p> * This takes the specified bean and replaces the target object. * The target must be a property of the bean and the update function must be able to replace the target. * The update must return a new bean, leaving the original unaltered. * <p> * If the target is not resolvable, or the target is already resolved, * then the specified input bean will be returned. * <p> * For example, this method might be used as follows: * <pre> * resolver.resolveLinksIn(bean, bean.getFoo(), resolved -> bean.toBuilder().foo(resolved).build()); * </pre> * <p> * This method is typically invoked from implementations of {@link Resolvable#resolveLinks(LinkResolver)}. * In that case, the above example would use {@code this} instead of {@code bean}. * * @param bean the target bean * @param target the target object within the bean * @param updateFn the update function * @return the updated bean */ public default <B, T> B resolveLinksIn(B bean, T target, Function<T, B> updateFn) { if (target instanceof Resolvable) { @SuppressWarnings("unchecked") Resolvable<T> resolvableTarget = (Resolvable<T>) target; T resolved = resolvableTarget.resolveLinks(this); if (resolved != target) { return updateFn.apply(resolved); } } return bean; } }