[DS-726] Add modular configuration

git-svn-id: http://scm.dspace.org/svn/repo/dspace/trunk@5665 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
Richard Rodgers
2010-10-26 21:59:50 +00:00
parent cb80f0cad4
commit 1b1cc00a34
2 changed files with 455 additions and 114 deletions

View File

@@ -50,6 +50,8 @@ import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.log4j.Category;
@@ -85,6 +87,9 @@ public class ConfigurationManager
/** The configuration properties */
private static Properties properties = null;
/** module configuration properties */
private static Map<String, Properties> moduleProps = null;
/** The default license */
private static String license;
@@ -102,16 +107,50 @@ public class ConfigurationManager
}
/**
* Discard all current properties - will force a reload from disk when
* any properties are requested.
*/
public static void flush()
{
properties = null;
}
/**
* Discard properties for a module - will force a reload from disk
* when any of module's properties are requested
*
* @param module the module name
*/
public static void flush(String module)
{
moduleProps.remove(module);
}
/**
* Returns all properties in main configuration
*
* @return properties - all non-modular properties
*/
public static Properties getProperties()
{
return getProperties(null);
}
/**
* Returns all properties for a given module
*
* @param module
* the name of the module
* @return properties - all module's properties
*/
public static Properties getProperties(String module)
{
if (properties == null)
{
loadConfig(null);
}
return (Properties)properties.clone();
Properties retProps =
(module != null) ? moduleProps.get(module) : properties;
return (Properties)retProps.clone();
}
/**
@@ -124,18 +163,83 @@ public class ConfigurationManager
* does not exist.
*/
public static String getProperty(String property)
{
return getProperty(null, property);
}
/**
* Get a module configuration property value.
*
* @param module
* the name of the module, or <code>null</code> for regular configuration
* property
* @param property
* the name (key) of the property
* @return
* the value of the property, or <code>null</code> if the
* property does not exist
*/
public static String getProperty(String module, String property)
{
if (properties == null)
{
loadConfig(null);
}
String propertyValue = properties.getProperty(property);
if (propertyValue != null)
String value = null;
if (module == null)
{
propertyValue = propertyValue.trim();
value = properties.getProperty(property);
}
return propertyValue;
else
{
Properties modProps = moduleProps.get(module);
if (modProps != null)
{
value = modProps.getProperty(property);
}
else
{
// look in regular properties with module name prepended
value = properties.getProperty(module + "." + property);
if (value == null) {
// try to find it in modules
File modFile = null;
try
{
modFile = new File(getProperty("dspace.dir") +
File.separator + "config" +
File.separator + "modules" +
File.separator + module + ".cfg");
if (modFile.exists())
{
modProps = new Properties();
modProps.load(new FileInputStream(modFile));
for (Enumeration pe = modProps.propertyNames(); pe.hasMoreElements(); )
{
String key = (String)pe.nextElement();
String ival = interpolate(key, modProps.getProperty(key), 1);
if (ival != null)
modProps.setProperty(key, ival);
}
moduleProps.put(module, modProps);
value = modProps.getProperty(property);
}
else
{
// log invalid request
warn("Requested configuration module: " + module + " not found");
}
}
catch (IOException ioE)
{
fatal("Can't load configuration: " + modFile.getAbsolutePath(), ioE);
}
}
}
}
return (value != null) ? value.trim() : null;
}
/**
@@ -153,6 +257,24 @@ public class ConfigurationManager
return getIntProperty(property, 0);
}
/**
* Get a module configuration property as an integer
*
* @param module
* the name of the module
*
* @param property
* the name of the property
*
* @return the value of the property. <code>0</code> is returned if the
* property does not exist. To differentiate between this case and
* when the property actually is zero, use <code>getProperty</code>.
*/
public static int getIntProperty(String module, String property)
{
return getIntProperty(module, property, 0);
}
/**
* Get a configuration property as an integer, with default
*
@@ -168,13 +290,35 @@ public class ConfigurationManager
* <code>getProperty</code>.
*/
public static int getIntProperty(String property, int defaultValue)
{
return getIntProperty(null, property, defaultValue);
}
/**
* Get a module configuration property as an integer, with default
*
* @param module
* the name of the module
*
* @param property
* the name of the property
*
* @param defaultValue
* value to return if property is not found or is not an Integer.
*
* @return the value of the property. <code>default</code> is returned if
* the property does not exist or is not an Integer. To differentiate between this case
* and when the property actually is false, use
* <code>getProperty</code>.
*/
public static int getIntProperty(String module, String property, int defaultValue)
{
if (properties == null)
{
loadConfig(null);
}
String stringValue = properties.getProperty(property);
String stringValue = getProperty(module, property);
int intValue = defaultValue;
if (stringValue != null)
@@ -192,33 +336,6 @@ public class ConfigurationManager
return intValue;
}
/**
* Get a configuration property and specify the fallback default
*
* @param property
* the name of the property
*
* @param defaultValue
* the default value of the property
*
* @return the value of the property or the default value if the property
* does not exist.
*/
public static String getProperty(String property, String defaultValue)
{
if (properties == null) {
loadConfig(null);
}
String propertyValue = properties.getProperty(property);
if (propertyValue != null) {
propertyValue = propertyValue.trim();
} else {
propertyValue = defaultValue;
}
return propertyValue;
}
/**
* Get a configuration property as a long
*
@@ -234,9 +351,27 @@ public class ConfigurationManager
return getLongProperty(property, 0);
}
/**
* Get a module configuration property as a long
*
* @param module
* the name of the module
* @param property
* the name of the property
*
* @return the value of the property. <code>0</code> is returned if the
* property does not exist. To differentiate between this case and
* when the property actually is zero, use <code>getProperty</code>.
*/
public static long getLongProperty(String module, String property)
{
return getLongProperty(module, property, 0);
}
/**
* Get a configuration property as an long, with default
*
*
* @param property
* the name of the property
*
@@ -249,13 +384,34 @@ public class ConfigurationManager
* <code>getProperty</code>.
*/
public static long getLongProperty(String property, int defaultValue)
{
return getLongProperty(null, property, defaultValue);
}
/**
* Get a configuration property as an long, with default
*
* @param the module, or <code>null</code> for regular property
*
* @param property
* the name of the property
*
* @param defaultValue
* value to return if property is not found or is not a Long.
*
* @return the value of the property. <code>default</code> is returned if
* the property does not exist or is not an Integer. To differentiate between this case
* and when the property actually is false, use
* <code>getProperty</code>.
*/
public static long getLongProperty(String module, String property, int defaultValue)
{
if (properties == null)
{
loadConfig(null);
}
String stringValue = properties.getProperty(property);
String stringValue = properties.getProperty(module, property);
long longValue = defaultValue;
if (stringValue != null)
@@ -277,7 +433,7 @@ public class ConfigurationManager
* Get the License
*
* @param
* licenseFile file name
* license file name
*
* @return
* license text
@@ -329,6 +485,7 @@ public class ConfigurationManager
}
catch (IOException ioe)
{
}
}
}
@@ -336,7 +493,6 @@ public class ConfigurationManager
return license;
}
/**
* Get a configuration property as a boolean. True is indicated if the value
* of the property is <code>TRUE</code> or <code>YES</code> (case
@@ -355,6 +511,26 @@ public class ConfigurationManager
return getBooleanProperty(property, false);
}
/**
* Get a module configuration property as a boolean. True is indicated if
* the value of the property is <code>TRUE</code> or <code>YES</code> (case
* insensitive.)
*
* @param the module, or <code>null</code> for regular property
*
* @param property
* the name of the property
*
* @return the value of the property. <code>false</code> is returned if
* the property does not exist. To differentiate between this case
* and when the property actually is false, use
* <code>getProperty</code>.
*/
public static boolean getBooleanProperty(String module, String property)
{
return getBooleanProperty(module, property, false);
}
/**
* Get a configuration property as a boolean, with default.
* True is indicated if the value
@@ -373,13 +549,37 @@ public class ConfigurationManager
* <code>getProperty</code>.
*/
public static boolean getBooleanProperty(String property, boolean defaultValue)
{
return getBooleanProperty(null, property, defaultValue);
}
/**
* Get a module configuration property as a boolean, with default.
* True is indicated if the value
* of the property is <code>TRUE</code> or <code>YES</code> (case
* insensitive.)
*
* @param the module, or <code>null</code> for regular property
*
* @param property
* the name of the property
*
* @param defaultValue
* value to return if property is not found.
*
* @return the value of the property. <code>default</code> is returned if
* the property does not exist. To differentiate between this case
* and when the property actually is false, use
* <code>getProperty</code>.
*/
public static boolean getBooleanProperty(String module, String property, boolean defaultValue)
{
if (properties == null)
{
loadConfig(null);
}
String stringValue = properties.getProperty(property);
String stringValue = getProperty(module, property);
if (stringValue != null)
{
@@ -399,14 +599,34 @@ public class ConfigurationManager
* @return an enumeration of all the keys in the DSpace configuration
*/
public static Enumeration<?> propertyNames()
{
return propertyNames(null);
}
/**
* Returns an enumeration of all the keys in a module configuration
*
* @param the module, or <code>null</code> for regular property
*
* @return an enumeration of all the keys in the module configuration,
* or <code>null</code> if the module does not exist.
*/
public static Enumeration<?> propertyNames(String module)
{
if (properties == null)
{
loadConfig(null);
}
if (module == null)
{
return properties.propertyNames();
}
if (moduleProps.containsKey(module))
{
return moduleProps.get(module).propertyNames();
}
return null;
}
/**
* Get the template for an email message. The message is suitable for
@@ -476,9 +696,7 @@ public class ConfigurationManager
email.setContent(contentBuffer.toString());
if (charset != null)
{
email.setCharset(charset);
}
return email;
}
@@ -552,8 +770,7 @@ public class ConfigurationManager
* Writes news to a text file.
*
* @param newsFile
* name of the news file to write, relative to the news file path.
*
* name of the news file to read in, relative to the news file path.
* @param news
* the text to be written to the file.
*/
@@ -584,10 +801,8 @@ public class ConfigurationManager
* Writes license to a text file.
*
* @param licenseFile
* name for the file into which the license will be written,
* name for the file int which license will be written,
* relative to the current directory.
* @param newLicense
* the text to be written to the file.
*/
public static void writeLicenseFile(String licenseFile, String newLicense)
{
@@ -663,7 +878,14 @@ public class ConfigurationManager
log.warn("Unable to access system properties, ignoring.", se);
}
if (configFile != null)
// should only occur after a flush()
if (loadedFile != null)
{
info("Reloading current config file: " + loadedFile.getAbsolutePath());
url = loadedFile.toURI().toURL();
}
else if (configFile != null)
{
info("Loading provided config file: " + configFile);
@@ -700,6 +922,7 @@ public class ConfigurationManager
else
{
properties = new Properties();
moduleProps = new HashMap<String, Properties>();
is = url.openStream();
properties.load(is);
@@ -707,7 +930,7 @@ public class ConfigurationManager
for (Enumeration<?> pe = properties.propertyNames(); pe.hasMoreElements(); )
{
String key = (String)pe.nextElement();
String value = interpolate(key, 1);
String value = interpolate(key, properties.getProperty(key), 1);
if (value != null)
{
properties.setProperty(key, value);
@@ -806,6 +1029,8 @@ public class ConfigurationManager
}
}
try
{
/*
@@ -877,13 +1102,13 @@ public class ConfigurationManager
* @return new value if it contains interpolations, or null
* if it had no variable references.
*/
private static String interpolate(String key, int level)
private static String interpolate(String key, String value, int level)
{
if (level > RECURSION_LIMIT)
{
throw new IllegalArgumentException("ConfigurationManager: Too many levels of recursion in configuration property variable interpolation, property=" + key);
}
String value = (String)properties.get(key);
//String value = (String)properties.get(key);
int from = 0;
StringBuffer result = null;
while (from < value.length())
@@ -907,7 +1132,7 @@ public class ConfigurationManager
}
if (properties.containsKey(var))
{
String ivalue = interpolate(var, level+1);
String ivalue = interpolate(var, properties.getProperty(var), level+1);
if (ivalue != null)
{
result.append(ivalue);
@@ -966,10 +1191,26 @@ public class ConfigurationManager
System.exit(0);
}
else if ((argv.length == 4) && argv[0].equals("-module") &&
argv[2].equals("-property"))
{
String val = getProperty(argv[1], argv[3]);
if (val != null)
{
System.out.println(val);
}
else
{
System.out.println("");
}
System.exit(0);
}
else
{
System.err
.println("Usage: ConfigurationManager OPTION\n -property prop.name get value of prop.name from dspace.cfg");
.println("Usage: ConfigurationManager OPTION\n [-module mod.name] -property prop.name get value of prop.name from module or dspace.cfg");
}
System.exit(1);

View File

@@ -55,7 +55,6 @@ import java.io.File;
import java.io.IOException;
import org.apache.log4j.Logger;
import org.dspace.content.crosswalk.DisseminationCrosswalk;
/**
* The Plugin Manager is a very simple component container. It creates and
@@ -116,7 +115,7 @@ public class PluginManager
// Predicate -- whether or not to cache this class. Ironically,
// the cacheability information is itself cached.
private static boolean cacheMe(Class implClass)
private static boolean cacheMe(String module, Class implClass)
{
if (cacheMeCache.containsKey(implClass))
{
@@ -125,7 +124,9 @@ public class PluginManager
else
{
String key = REUSABLE_PREFIX+implClass.getName();
boolean reusable = ConfigurationManager.getBooleanProperty(key, true);
boolean reusable = (module != null) ?
ConfigurationManager.getBooleanProperty(module, key, true) :
ConfigurationManager.getBooleanProperty(key, true);
cacheMeCache.put(implClass, Boolean.valueOf(reusable));
return reusable;
}
@@ -147,21 +148,38 @@ public class PluginManager
*/
public static Object getSinglePlugin(Class interfaceClass)
throws PluginConfigurationError, PluginInstantiationException
{
return getSinglePlugin(null, interfaceClass);
}
/**
* Returns an instance of the singleton (single) plugin implementing
* the given interface. There must be exactly one single plugin
* configured for this interface, otherwise the
* <code>PluginConfigurationError</code> is thrown.
* <p>
* Note that this is the only "get plugin" method which throws an
* exception. It is typically used at initialization time to set up
* a permanent part of the system so any failure is fatal.
*
* @param name of config module, or <code>null</code> for standard location
* @param interfaceClass interface Class object
* @return instance of plugin
* @throws PluginConfigurationError
*/
public static Object getSinglePlugin(String module, Class interfaceClass)
throws PluginConfigurationError, PluginInstantiationException
{
String iname = interfaceClass.getName();
// configuration format is prefix.<interface> = <classname>
String classname = ConfigurationManager.getProperty(SINGLE_PREFIX+iname);
String classname = getConfigProperty(module, SINGLE_PREFIX+iname);
if (classname != null)
{
return getAnonymousPlugin(classname.trim());
}
return getAnonymousPlugin(module, classname.trim());
else
{
throw new PluginConfigurationError("No Single Plugin configured for interface \""+iname+"\"");
}
}
// cache of config data for Sequence Plugins; format its
// <interface-name> -> [ <classname>.. ] (value is Array)
@@ -181,6 +199,25 @@ public class PluginManager
*/
public static Object[] getPluginSequence(Class intfc)
throws PluginInstantiationException
{
return getPluginSequence(null, intfc);
}
/**
* Returns instances of all plugins that implement the interface
* intface, in an Array. Returns an empty array if no there are no
* matching plugins.
* <p>
* The order of the plugins in the array is the same as their class
* names in the configuration's value field.
*
* @param module name of config module, or <code>null</code> for standard
* @param intfc interface for which to find plugins.
* @return an array of plugin instances; if none are
* available an empty array is returned.
*/
public static Object[] getPluginSequence(String module, Class intfc)
throws PluginInstantiationException
{
// cache the configuration for this interface after grovelling it once:
// format is prefix.<interface> = <classname>
@@ -188,7 +225,7 @@ public class PluginManager
String classname[] = null;
if (!sequenceConfig.containsKey(iname))
{
String val = ConfigurationManager.getProperty(SEQUENCE_PREFIX+iname);
String val = getConfigProperty(module, SEQUENCE_PREFIX+iname);
if (val == null)
{
log.warn("No Configuration entry found for Sequence Plugin interface="+iname);
@@ -206,23 +243,24 @@ public class PluginManager
for (int i = 0; i < classname.length; ++i)
{
log.debug("Adding Sequence plugin for interface= "+iname+", class="+classname[i]);
result[i] = getAnonymousPlugin(classname[i]);
result[i] = getAnonymousPlugin(module, classname[i]);
}
return result;
}
// Map of cached (reusable) single plugin instances - class -> instance.
private static Map<Serializable, Object> anonymousInstanceCache = new HashMap<Serializable, Object>();
// Get possibly-cached plugin instance for un-named plugin,
// this is shared by Single and Sequence plugins.
private static Object getAnonymousPlugin(String classname)
private static Object getAnonymousPlugin(String module, String classname)
throws PluginInstantiationException
{
try
{
Class pluginClass = Class.forName(classname);
if (cacheMe(pluginClass))
if (cacheMe(module, pluginClass))
{
Object cached = anonymousInstanceCache.get(pluginClass);
if (cached == null)
@@ -260,7 +298,7 @@ public class PluginManager
private static Map<Serializable, Object> namedInstanceCache = new HashMap<Serializable, Object>();
// load and cache configuration data for the given interface.
private static void configureNamedPlugin(String iname)
private static void configureNamedPlugin(String module, String iname)
throws ClassNotFoundException
{
int found = 0;
@@ -276,7 +314,7 @@ public class PluginManager
// 1. Get classes named by the configuration. format is:
// plugin.named.<INTF> = <CLASS> = <name>, <name> [,] \
// <CLASS> = <name>, <name> [ ... ]
String namedVal = ConfigurationManager.getProperty(NAMED_PREFIX+iname);
String namedVal = getConfigProperty(module, NAMED_PREFIX+iname);
if (namedVal != null)
{
namedVal = namedVal.trim();
@@ -307,7 +345,7 @@ public class PluginManager
// 2. Get Self-named config entries:
// format is plugin.selfnamed.<INTF> = <CLASS> , <CLASS> ..
String selfNamedVal = ConfigurationManager.getProperty(SELFNAMED_PREFIX+iname);
String selfNamedVal = getConfigProperty(module, SELFNAMED_PREFIX+iname);
if (selfNamedVal != null)
{
String classnames[] = selfNamedVal.trim().split("\\s*,\\s*");
@@ -380,11 +418,28 @@ public class PluginManager
*/
public static Object getNamedPlugin(Class intfc, String name)
throws PluginInstantiationException
{
return getNamedPlugin(null, intfc, name);
}
/**
* Returns an instance of a plugin that implements the interface
* intface and is bound to a name matching name. If there is no
* matching plugin, it returns null. The names are matched by
* String.equals().
*
* @param module config module, or <code>null</code> for standard location
* @param intfc the interface class of the plugin
* @param name under which the plugin implementation is configured.
* @return instance of plugin implementation, or null if there is no match or an error.
*/
public static Object getNamedPlugin(String module, Class intfc, String name)
throws PluginInstantiationException
{
try
{
String iname = intfc.getName();
configureNamedPlugin(iname);
configureNamedPlugin(module, iname);
String key = iname + SEP + name;
String cname = namedPluginClasses.get(key);
if (cname == null)
@@ -394,7 +449,7 @@ public class PluginManager
else
{
Class pluginClass = Class.forName(cname);
if (cacheMe(pluginClass))
if (cacheMe(module, pluginClass))
{
String nkey = pluginClass.getName() + SEP + name;
Object cached = namedInstanceCache.get(nkey);
@@ -454,11 +509,27 @@ public class PluginManager
*/
public static boolean hasNamedPlugin(Class intfc, String name)
throws PluginInstantiationException
{
return hasNamedPlugin(null, intfc, name);
}
/**
* Returns whether a plugin exists which implements the specified interface
* and has a specified name. If a matching plugin is found to be configured,
* return true. If there is no matching plugin, return false.
*
* @param module the config module or <code>null</code> for regular location
* @param intfc the interface class of the plugin
* @param name under which the plugin implementation is configured.
* @return true if plugin was found to be configured, false otherwise
*/
public static boolean hasNamedPlugin(String module, Class intfc, String name)
throws PluginInstantiationException
{
try
{
String iname = intfc.getName();
configureNamedPlugin(iname);
configureNamedPlugin(module, iname);
String key = iname + SEP + name;
return namedPluginClasses.get(key) != null;
}
@@ -468,6 +539,7 @@ public class PluginManager
e.toString(), e);
}
}
/**
* Returns all of the names under which a named plugin implementing
* the interface intface can be requested (with getNamedPlugin()).
@@ -482,11 +554,30 @@ public class PluginManager
* available an empty array is returned.
*/
public static String[] getAllPluginNames(Class intfc)
{
return getAllPluginNames(null, intfc);
}
/**
* Returns all of the names under which a named plugin implementing
* the interface intface can be requested (with getNamedPlugin()).
* The array is empty if there are no matches. Use this to populate
* a menu of plugins for interactive selection, or to document what
* the possible choices are.
* <p>
* NOTE: The names are NOT returned in any deterministic order.
*
* @param module the module name
* @param intfc plugin interface for which to return names.
* @return an array of strings with every name; if none are
* available an empty array is returned.
*/
public static String[] getAllPluginNames(String module, Class intfc)
{
try
{
String iname = intfc.getName();
configureNamedPlugin(iname);
configureNamedPlugin(module, iname);
String prefix = iname + SEP;
ArrayList<String> result = new ArrayList<String>();
@@ -603,7 +694,7 @@ public class PluginManager
{
try
{
configureNamedPlugin(iname);
configureNamedPlugin(null, iname);
}
catch (ClassNotFoundException ce)
{
@@ -611,6 +702,15 @@ public class PluginManager
}
}
// get module-specific, or generic configuration property
private static String getConfigProperty(String module, String property)
{
if (module != null) {
return ConfigurationManager.getProperty(module, property);
}
return ConfigurationManager.getProperty(property);
}
/**
* Validate the entries in the DSpace Configuration relevant to
* PluginManager. Look for inconsistencies, illegal syntax, etc.