/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.engine;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.opengamma.DataNotFoundException;
import com.opengamma.component.tool.ToolContextUtils;
import com.opengamma.core.config.ConfigSource;
import com.opengamma.core.convention.ConventionSource;
import com.opengamma.core.exchange.ExchangeSource;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeriesSource;
import com.opengamma.core.holiday.HolidaySource;
import com.opengamma.core.legalentity.LegalEntitySource;
import com.opengamma.core.marketdatasnapshot.MarketDataSnapshotSource;
import com.opengamma.core.position.PositionSource;
import com.opengamma.core.region.RegionSource;
import com.opengamma.core.security.SecuritySource;
import com.opengamma.financial.convention.ConventionBundleSource;
import com.opengamma.financial.tool.ToolContext;
import com.opengamma.util.ArgumentChecker;
/**
* Loads components using {@link ToolContext} configuration and puts them in a map.
* This isn't a long-term solution but will do for the time being.
* TODO rename ComponentLookup or create interface and have this implement it
* TODO would it be better to compose by delegation/chaining instead of with()?
*/
public final class ComponentMap {
private static final Logger s_logger = LoggerFactory.getLogger(ComponentMap.class);
/**
* The empty component map.
*/
public static final ComponentMap EMPTY = new ComponentMap(Collections.<Class<?>, Object>emptyMap());
private final ImmutableMap<Class<?>, Object> _components;
private ComponentMap(Map<Class<?>, Object> components) {
_components = ImmutableMap.copyOf(components);
}
/**
* @param toolContext a tool context containing the components
* @return The available components, keyed by type.
*/
public static ComponentMap loadComponents(ToolContext toolContext) {
ArgumentChecker.notNull(toolContext, "toolContext");
ImmutableMap.Builder<Class<?>, Object> builder = ImmutableMap.builder();
builder.put(ConfigSource.class, toolContext.getConfigSource());
builder.put(ConventionBundleSource.class, toolContext.getConventionBundleSource());
builder.put(ConventionSource.class, toolContext.getConventionSource());
builder.put(ExchangeSource.class, toolContext.getExchangeSource());
builder.put(HolidaySource.class, toolContext.getHolidaySource());
builder.put(LegalEntitySource.class, toolContext.getLegalEntitySource());
builder.put(PositionSource.class, toolContext.getPositionSource());
builder.put(RegionSource.class, toolContext.getRegionSource());
builder.put(SecuritySource.class, toolContext.getSecuritySource());
builder.put(HistoricalTimeSeriesSource.class, toolContext.getHistoricalTimeSeriesSource());
builder.put(MarketDataSnapshotSource.class, toolContext.getMarketDataSnapshotSource());
return new ComponentMap(builder.build());
}
/**
* @param location Location of the component config, can be a classpath: or file: resource or the URL of a remote
* server
* @return The available components, keyed by type.
*/
public static ComponentMap loadComponents(String location) {
ArgumentChecker.notEmpty(location, "location");
s_logger.info("Loading components from {}", location);
ToolContext toolContext = ToolContextUtils.getToolContext(location, ToolContext.class);
return loadComponents(toolContext);
}
/**
* Returns a component or throws an exception if there is no component available of the required type.
* @param type The required component type
* @param <T> The required component type
* @return A component of the required type, not null
* @throws DataNotFoundException If there is no component of the specified type
*/
@SuppressWarnings("unchecked")
public <T> T getComponent(Class<T> type) {
T component = (T) _components.get(ArgumentChecker.notNull(type, "type"));
if (component == null) {
throw new DataNotFoundException("No component found of type " + type);
}
return component;
}
/**
* Returns a component or null if there is no component available of the required type.
* @param type The required component type
* @param <T> The required component type
* @return A component of the required type or null if there isn't one
*/
@SuppressWarnings("unchecked")
public <T> T findComponent(Class<T> type) {
return (T) _components.get(ArgumentChecker.notNull(type, "type"));
}
/**
* Returns a copy this {@link ComponentMap} with the passed components
* overlaid on top.
* @param components the components to add to the copy
* @return a new {@link ComponentMap} instance
*/
public ComponentMap with(Map<Class<?>, Object> components) {
ArgumentChecker.notNull(components, "components");
Map<Class<?>, Object> newComponents = Maps.newHashMap(_components);
//use a new hashmap to build rather than ImmutableMap.builder() in case
//the key is overwriting another (in which case the builder throws).
newComponents.putAll(components);
return new ComponentMap(ImmutableMap.copyOf(newComponents));
}
/**
* Returns a copy this {@link ComponentMap} with the passed component
* overlaid on top.
* @param type the type of the component
* @param component the component
* @param <T> the type to use to register the component
* @param <U> the type of the component to register, a subclass of T
* @return a new {@link ComponentMap} instance
*/
public <T, U extends T> ComponentMap with(Class<T> type, U component) {
ArgumentChecker.notNull(type, "type");
ArgumentChecker.notNull(component, "component");
//use a new hashmap to build rather than ImmutableMap.builder() in case
//the key is overwriting another (in which case the builder throws).
Map<Class<?>, Object> newComponents = Maps.newHashMap(_components);
newComponents.put(type, component);
return new ComponentMap(ImmutableMap.copyOf(newComponents));
}
public static ComponentMap of(Map<Class<?>, Object> components) {
ArgumentChecker.notNull(components, "components");
return new ComponentMap(ImmutableMap.copyOf(components));
}
/**
* @return The components keyed by type
*/
public Map<Class<?>, Object> getComponents() {
return _components;
}
/**
* @return The types of the available components
*/
public Set<Class<?>> getComponentTypes() {
return _components.keySet();
}
}