package org.marketcetera.module; import org.marketcetera.util.misc.ClassVersion; import org.marketcetera.util.log.SLF4JLoggerProxy; import org.marketcetera.util.log.I18NBoundMessage1P; import java.util.Properties; import java.util.Map; import java.util.WeakHashMap; import java.io.InputStream; import java.io.IOException; /* $License$ */ /** * Provides a properties file based configuration. This provider looks for * a unique properties file per module provider and uses that properties * file to resolve the default attribute values for the module factory * and the module instances from that provider. * <p> * The property file name is constructed from the module provider name. * <code>provider-type_provider-name.properties</code>. The properties files * are loaded via the classloader. However, the recommended location for * the properties file is <code><application-home>/modules/conf</code> * <p> * Within the property file, the attribute values are encoded as * <code>instance-name.attribute-name=attribute-value</code>. * Default attribute values, that apply to all instances can be specified as * <code>.attribute-name=attribute-value</code. * <p> * For factory attributes, "<code>instance-name.</code>" is excluded from * the property name, ie. the attribute value is specified as * <code>attribute-name=attribute-value</code> * * @author anshul@marketcetera.com * @version $Id: PropertiesConfigurationProvider.java 16154 2012-07-14 16:34:05Z colin $ * @since 1.0.0 */ @ClassVersion("$Id: PropertiesConfigurationProvider.java 16154 2012-07-14 16:34:05Z colin $") //$NON-NLS-1$ public class PropertiesConfigurationProvider implements ModuleConfigurationProvider { /** * Creates a new instance. * * @param inLoader the classloader that should be used to fetch the * properties files. */ public PropertiesConfigurationProvider(ClassLoader inLoader) { if(inLoader == null) { throw new NullPointerException(); } mLoader = inLoader; } @Override public String getDefaultFor(ModuleURN inURN, String inAttribute) throws ModuleException { SLF4JLoggerProxy.debug(this, "Looking default value of attribute {} for {}", //$NON-NLS-1$ inAttribute, inURN); String propertiesFile = new StringBuilder(). append(inURN.providerType()). append("_"). //$NON-NLS-1$ append(inURN.providerName()). append(".properties").toString(); //$NON-NLS-1$ Properties p; synchronized(this) { p = mCache.get(propertiesFile); // if the property is not found in the cache // try loading it. if(p == null) { InputStream is = mLoader. getResourceAsStream(propertiesFile); if(is != null) { p = new Properties(); try { p.load(is); // Only add properties to the cache // if it was loaded successfully. mCache.put(propertiesFile, p); } catch (IOException e) { Messages.LOG_ERROR_READ_DEFAULT_CONFIG.warn(this, e, propertiesFile, inURN, inAttribute); throw new ModuleException(e, new I18NBoundMessage1P( Messages.ERROR_READ_PROPERTIES,propertiesFile)); } } } } if(p != null && !p.isEmpty()) { if(inURN.instanceURN()) { // find the instance specific value String value = p.getProperty(inURN.instanceName() + "." + inAttribute); //$NON-NLS-1$ if(value != null) { // if the instance specific value is found // return it return value; } else { // return property value for all instances return p.getProperty("." + inAttribute); //$NON-NLS-1$ } } else { return p.getProperty(inAttribute); } } return null; } @Override public void refresh() { mCache.clear(); } private final Map<String,Properties> mCache = new WeakHashMap<String,Properties>(); private final ClassLoader mLoader; }