/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.convention;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentMap;
import com.google.common.collect.Maps;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.ClassUtils;
/**
* An abstract factory for named instances.
* <p>
* A named instance is a type where each instance is uniquely identified by a name.
* This factory provides access to all the instances.
* <p>
* Implementations should typically be singletons with a public static factory instance
* named 'INSTANCE' accessible using {@link ClassUtils#singletonInstance(Class)}.
*
* @param <T> type of objects returned
*/
public abstract class AbstractNamedInstanceFactory<T extends NamedInstance>
implements NamedInstanceFactory<T> {
/**
* The named instance type.
*/
private final Class<T> _type;
/**
* Map of primary instances.
*/
private final ConcurrentMap<String, T> _instanceMap = Maps.newConcurrentMap();
/**
* Map of all instances.
*/
private final ConcurrentMap<String, T> _instanceMapAltNames = Maps.newConcurrentMap();
/**
* Lookup map of instances keyed by lower case.
*/
private final ConcurrentMap<String, T> _lookupMap = Maps.newConcurrentMap();
/**
* Creates the factory.
*
* @param type the type of named instance, not null
*/
protected AbstractNamedInstanceFactory(Class<T> type) {
_type = ArgumentChecker.notNull(type, "type");
}
//-------------------------------------------------------------------------
/**
* Adds an instance, potentially using a different name.
*
* @param instance the named instance, not null
* @param alternativeNames the alternative names to use in addition to the instance name, not null
* @return the instance, not null
*/
protected T addInstance(T instance, String... alternativeNames) {
ArgumentChecker.notNull(instance, "instance");
ArgumentChecker.notNull(alternativeNames, "alternativeNames");
_instanceMap.put(instance.getName(), instance);
_instanceMapAltNames.put(instance.getName(), instance);
_lookupMap.put(instance.getName().toLowerCase(Locale.ENGLISH), instance);
for (String altName : alternativeNames) {
_instanceMapAltNames.put(altName, instance);
_lookupMap.put(altName.toLowerCase(Locale.ENGLISH), instance);
}
return instance;
}
/**
* Loads instances from a properties file based on the type.
* <p>
* The properties file must be a name key to a class name.
*/
protected void loadFromProperties() {
loadFromProperties(_type.getName());
}
/**
* Loads instances from a properties file.
* <p>
* The properties file must be a name key to a class name.
*
* @param bundleName the bundle name, not null
*/
protected void loadFromProperties(String bundleName) {
ArgumentChecker.notNull(bundleName, "bundleName");
final ResourceBundle bundle = ResourceBundle.getBundle(bundleName);
final Map<String, T> instances = Maps.newHashMap();
for (String name : bundle.keySet()) {
String implementationType = bundle.getString(name);
T instance = instances.get(implementationType);
if (instance == null) {
try {
instance = ClassUtils.loadClassRuntime(implementationType).asSubclass(_type).newInstance();
instances.put(implementationType, instance);
} catch (Exception ex) {
throw new OpenGammaRuntimeException("Error loading properties for " + _type.getSimpleName(), ex);
}
}
addInstance(instance, name);
}
}
//-------------------------------------------------------------------------
@Override
public T instance(final String name) {
ArgumentChecker.notNull(name, "name");
final T result = _lookupMap.get(name.toLowerCase(Locale.ENGLISH));
if (result == null) {
throw new IllegalArgumentException("Unknown " + _type.getSimpleName() + ": " + name);
}
return result;
}
@Override
public Map<String, T> instanceMap() {
return Collections.unmodifiableMap(_instanceMap);
}
@Override
public Map<String, T> instanceMapWithAlternateNames() {
return Collections.unmodifiableMap(_instanceMapAltNames);
}
//-------------------------------------------------------------------------
@Override
public String toString() {
return "NamedInstanceFactory[" + _type.getSimpleName() + ",size=" + _instanceMapAltNames.size() + "]";
}
}