/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.core.link; import java.io.Serializable; import java.util.Collection; import java.util.Iterator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.opengamma.DataNotFoundException; import com.opengamma.core.config.ConfigSource; import com.opengamma.core.config.impl.ConfigItem; import com.opengamma.id.VersionCorrection; import com.opengamma.service.ServiceContext; import com.opengamma.service.VersionCorrectionProvider; /** * Link resolver to resolve config links using a ServiceContext. * * @param <T> the type of config object to be resolved */ /* package */ final class ServiceContextConfigLinkResolver<T> extends SourceLinkResolver<String, T, ConfigSource> implements Serializable { /** * Logger for the class. */ private static final Logger s_logger = LoggerFactory.getLogger(ServiceContextConfigLinkResolver.class); /** * Creates the resolver using the default service context. */ /* package */ ServiceContextConfigLinkResolver() { super(); } /** * Creates the resolver using the supplied service context. * * @param serviceContext the service context to use when resolving the link */ /* package */ ServiceContextConfigLinkResolver(ServiceContext serviceContext) { super(serviceContext); } @Override protected Class<ConfigSource> getSourceClass() { return ConfigSource.class; } @Override protected VersionCorrection getVersionCorrection(VersionCorrectionProvider vcProvider) { return vcProvider.getConfigVersionCorrection(); } @Override protected T executeQuery(ConfigSource configSource, Class<T> type, String name, VersionCorrection versionCorrection) { // The database stores config items with exact type, but we may want to search // with a more general type. We therefore may need to try the search twice. final T result = findWithMatchingType(configSource, type, name, versionCorrection); return result != null ? result : findWithGeneralType(configSource, type, name, versionCorrection); } private T findWithMatchingType(ConfigSource configSource, Class<T> type, String identifier, VersionCorrection versionCorrection) { return selectResult(type, identifier, configSource.get(type, identifier, versionCorrection)); } @SuppressWarnings("unchecked") private T findWithGeneralType(ConfigSource configSource, final Class<T> type, String identifier, VersionCorrection versionCorrection) { // Filter the items so we only have ones with compatible types Collection<ConfigItem<Object>> allMatches = configSource.get(Object.class, identifier, versionCorrection); Iterable<ConfigItem<Object>> results = filterForCorrectType(allMatches, type); final T result = (T) selectResult(type, identifier, results); if (result != null) { return result; } else { throw new DataNotFoundException("No config found with type: [" + type.getName() + "], id: [" + identifier + "] and versionCorrection: [" + versionCorrection + "]"); } } private Iterable<ConfigItem<Object>> filterForCorrectType(Collection<ConfigItem<Object>> allMatches, Class<T> type) { return Iterables.filter(allMatches, typeMatcher(type)); } /** * Predicate which can be used to check that each item passed to * it is of the required type. * * @param type the type to check items are, subclasses of the type will also match * @return the predicate to perform the type matching */ private Predicate<ConfigItem<Object>> typeMatcher(final Class<T> type) { return new Predicate<ConfigItem<Object>>() { @Override public boolean apply(ConfigItem<Object> item) { return type.isAssignableFrom(item.getValue().getClass()); } }; } private <R> R selectResult(Class<T> type, String identifier, Iterable<ConfigItem<R>> results) { final Iterator<ConfigItem<R>> iterator = results.iterator(); return iterator.hasNext() ? selectFirst(type, identifier, iterator) : null; } private <R> R selectFirst(Class<T> type, String identifier, Iterator<ConfigItem<R>> iterator) { R result = iterator.next().getValue(); if (iterator.hasNext()) { s_logger.warn("Found multiple matching config results for type: {} and name: {} - returning first found", type.getName(), identifier); } return result; } }