package org.marketcetera.metrics;
import org.marketcetera.util.misc.ClassVersion;
import org.marketcetera.util.log.SLF4JLoggerProxy;
import java.util.Properties;
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
import java.io.IOException;
import java.io.InputStream;
/* $License$ */
/**
* Provides static mechanisms to configure the metrics instrumentation.
* By default, this mechanism looks for a file named
* {@link #METRICS_PROPERTIES_FILE_NAME metc_metrics.properties} in the
* classpath and loads the property values from it.
* <p>
* If desired, a custom mechanism can be provided to resolve property
* values by subclassing this class and setting that instance value via
* {@link #setInstance(Configurator)}.
* <p>
* The property {@link #PROPERTY_METRICS_ENABLE metc.metrics.enable} has
* special significance in that it's used to enable / disable instrumentation.
* <p>
* Note that these property values are only read once. These values are
* not expected to change after they have been initialized.
*
* @author anshul@marketcetera.com
* @version $Id: Configurator.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: Configurator.java 16154 2012-07-14 16:34:05Z colin $")
public abstract class Configurator {
/**
* The property name used to enable / disable metrics.
*/
public static final String PROPERTY_METRICS_ENABLE =
"metc.metrics.enable"; //$NON-NLS-1$
/**
* Returns the value for the supplied property name.
*
* @param inName the property name.
* @param inDefaultValue the default value for the property, if the
* property value is not available or if a configurator instance is not
* configured.
*
* @return the property value.
*/
public static String getProperty(String inName, String inDefaultValue) {
String value = null;
Configurator instance = getInstance();
if (instance != null && inName != null) {
value = instance.getPropertyValue(inName);
}
value = value == null
? inDefaultValue
: value;
SLF4JLoggerProxy.debug(Configurator.class,
"Property Name {}, Value {}", //$NON-NLS-1$
inName, value);
sReportedValues.put(inName, value);
return value;
}
/**
* Returns the set of properties and their values as have been returned
* by invocations to {@link #getProperty(String, String)}.
* <p>
* Only the reported values can be returned as the Configurator
* doesn't provide means to list all the available properties.
* <p>
* The goal of this API is to enable runtime verification of the
* property values. So that anybody running performance tests can
* be sure how the instrumentation was configured when running
* the performance tests.
*
* @return the set of properties and their reported values.
*/
public static Map<String,String> getReportedValues() {
synchronized (sReportedValues) {
return new HashMap<String,String>(sReportedValues);
}
}
/**
* Sets the configurator instance that should be used for resolving
* property values.
*
* @param inInstance the configurator instnace. If set to null, all
* property values resolve to a null value.s
*/
public synchronized static void setInstance(Configurator inInstance) {
sInstance = inInstance;
sInitialized = true;
}
/**
* Clears the reported values. This method has been added for testing.
* Its not meant for use by the clients of this class.
*/
static void clearReportedValues() {
sReportedValues.clear();
}
/**
* Fetches the current configurator instance that should be used for
* resolving property values.
* <p>
* If the configurator has not been initialized, a property file based
* configurator, that resolves property values based on a file named
* {@link #METRICS_PROPERTIES_FILE_NAME} in the classpath, is initialized.
*
* @return the current configurator instance.
*/
private synchronized static Configurator getInstance() {
if(!sInitialized) {
setInstance(new PropertyFileConfigurator(Configurator.class.
getResourceAsStream(METRICS_PROPERTIES_FILE_NAME)));
}
return sInstance;
}
/**
* The current configurator instance.
*/
private static Configurator sInstance;
/**
* If the configurator has been initialized.
*/
private static boolean sInitialized = false;
/**
* The property key value pairs that have been queried via
* {@link #getProperty(String, String)}.
*/
private static final Map<String,String> sReportedValues =
Collections.synchronizedMap(new HashMap<String,String>());
/**
* This method is implemented by the subclasses to fetch the property
* value for the supplied property name.
*
* @param inName the property name.
*
* @return property value if available, null otherwise.
*/
protected abstract String getPropertyValue(String inName);
/**
* A configurator that initializes itself from a stream that contains
* properties as specified by {@link Properties#load(java.io.InputStream)}.
*/
private static class PropertyFileConfigurator extends Configurator {
/**
* Creates an instance.
*
* @param inStream the input stream that contains the property
* key value pairs. If null, the configurator return null values
* for all property names.
*/
public PropertyFileConfigurator(InputStream inStream) {
mProperties = new Properties();
if(inStream == null) {
return;
}
try {
try {
mProperties.load(inStream);
} finally {
inStream.close();
}
} catch (IOException e) {
Messages.LOG_ERR_LOADING_PROPERTIES.warn(this, e, inStream);
}
}
@Override
protected String getPropertyValue(String inName) {
return mProperties.getProperty(inName);
}
private final Properties mProperties;
}
/**
* The name of the properties file that is used to resolve property values.
* This properties file is looked for in the application's classpath.
*/
public static final String METRICS_PROPERTIES_FILE_NAME =
"/metc_metrics.properties"; //$NON-NLS-1$
}