diff --git a/dspace-api/src/main/java/org/dspace/core/ConfigurationManager.java b/dspace-api/src/main/java/org/dspace/core/ConfigurationManager.java index ae84167528..3edfec10a2 100644 --- a/dspace-api/src/main/java/org/dspace/core/ConfigurationManager.java +++ b/dspace-api/src/main/java/org/dspace/core/ConfigurationManager.java @@ -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; @@ -84,6 +86,9 @@ public class ConfigurationManager /** The configuration properties */ private static Properties properties = null; + + /** module configuration properties */ + private static Map 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 null for regular configuration + * property + * @param property + * the name (key) of the property + * @return + * the value of the property, or null 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; } /** @@ -152,6 +256,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. 0 is returned if the + * property does not exist. To differentiate between this case and + * when the property actually is zero, use getProperty. + */ + public static int getIntProperty(String module, String property) + { + return getIntProperty(module, property, 0); + } /** * Get a configuration property as an integer, with default @@ -169,56 +291,51 @@ public class ConfigurationManager */ public static int getIntProperty(String property, int defaultValue) { - if (properties == null) - { - loadConfig(null); - } + 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. default 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 + * getProperty. + */ + public static int getIntProperty(String module, String property, int defaultValue) + { + if (properties == null) + { + loadConfig(null); + } + + String stringValue = getProperty(module, property); + int intValue = defaultValue; - String stringValue = properties.getProperty(property); - int intValue = defaultValue; - - if (stringValue != null) - { - try - { - intValue = Integer.parseInt(stringValue.trim()); - } - catch (NumberFormatException e) - { - warn("Warning: Number format error in property: " + property); - } + if (stringValue != null) + { + try + { + intValue = Integer.parseInt(stringValue.trim()); + } + catch (NumberFormatException e) + { + warn("Warning: Number format error in property: " + property); + } } 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 * @@ -233,9 +350,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. 0 is returned if the + * property does not exist. To differentiate between this case and + * when the property actually is zero, use getProperty. + */ + 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 * getProperty. */ 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 null 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. default 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 + * getProperty. + */ + 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,9 +433,9 @@ public class ConfigurationManager * Get the License * * @param - * licenseFile file name - * - * @return + * license file name + * + * @return * license text * */ @@ -305,7 +461,7 @@ public class ConfigurationManager fatal("Can't load configuration", e); // FIXME: Maybe something more graceful here, but with the - // configuration we can't do anything + // configuration we can't do anything throw new IllegalStateException("Failed to read default license.", e); } finally @@ -313,7 +469,7 @@ public class ConfigurationManager if (br != null) { try - { + { br.close(); } catch (IOException ioe) @@ -324,11 +480,12 @@ public class ConfigurationManager if (fr != null) { try - { + { fr.close(); } 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 TRUE or YES (case @@ -354,8 +510,28 @@ 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 TRUE or YES (case + * insensitive.) + * + * @param the module, or null for regular property + * + * @param property + * the name of the property + * + * @return the value of the property. false is returned if + * the property does not exist. To differentiate between this case + * and when the property actually is false, use + * getProperty. + */ + 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 * of the property is TRUE or YES (case @@ -373,13 +549,37 @@ public class ConfigurationManager * getProperty. */ 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 TRUE or YES (case + * insensitive.) + * + * @param the module, or null 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. default is returned if + * the property does not exist. To differentiate between this case + * and when the property actually is false, use + * getProperty. + */ + 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,13 +599,33 @@ 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 null for regular property + * + * @return an enumeration of all the keys in the module configuration, + * or null if the module does not exist. + */ + public static Enumeration propertyNames(String module) { if (properties == null) { loadConfig(null); } - - return properties.propertyNames(); + if (module == null) + { + return properties.propertyNames(); + } + if (moduleProps.containsKey(module)) + { + return moduleProps.get(module).propertyNames(); + } + return null; } /** @@ -476,9 +696,7 @@ public class ConfigurationManager email.setContent(contentBuffer.toString()); if (charset != null) - { email.setCharset(charset); - } return email; } @@ -514,7 +732,7 @@ public class ConfigurationManager * Reads news from a text file. * * @param newsFile - * name of the news file to read in, relative to the news file path. + * name of the news file to read in, relative to the news file path. */ public static String readNewsFile(String newsFile) { @@ -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) { @@ -662,8 +877,15 @@ public class ConfigurationManager // This isn't really a fatal error though, so catch and ignore 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(); 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); @@ -729,11 +952,11 @@ public class ConfigurationManager if (is != null) { try - { + { is.close(); } catch (IOException ioe) - { + { } } } @@ -777,20 +1000,20 @@ public class ConfigurationManager try { br.close(); - } + } catch (IOException ioe) - { + { } } if (ir != null) { try - { + { ir.close(); - } + } catch (IOException ioe) - { + { } } @@ -801,11 +1024,13 @@ public class ConfigurationManager fir.close(); } catch (IOException ioe) - { + { } } } + + try { /* @@ -851,7 +1076,7 @@ public class ConfigurationManager if(logConfigFile.exists()) { info("Loading: " + dsLogConfiguration); - + OptionConverter.selectAndConfigure(logConfigFile.toURI() .toURL(), null, org.apache.log4j.LogManager .getLoggerRepository()); @@ -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); @@ -915,7 +1140,7 @@ public class ConfigurationManager } else { - result.append((String) properties.getProperty(var)); + result.append((String)properties.getProperty(var)); } } else @@ -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); diff --git a/dspace-api/src/main/java/org/dspace/core/PluginManager.java b/dspace-api/src/main/java/org/dspace/core/PluginManager.java index 2e769c18e6..261b26c770 100755 --- a/dspace-api/src/main/java/org/dspace/core/PluginManager.java +++ b/dspace-api/src/main/java/org/dspace/core/PluginManager.java @@ -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)) { @@ -124,8 +123,10 @@ public class PluginManager } else { - String key = REUSABLE_PREFIX+implClass.getName(); - boolean reusable = ConfigurationManager.getBooleanProperty(key, true); + String key = REUSABLE_PREFIX+implClass.getName(); + boolean reusable = (module != null) ? + ConfigurationManager.getBooleanProperty(module, key, true) : + ConfigurationManager.getBooleanProperty(key, true); cacheMeCache.put(implClass, Boolean.valueOf(reusable)); return reusable; } @@ -147,22 +148,39 @@ 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 + * PluginConfigurationError is thrown. + *

+ * 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 null 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. = - 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 + "\""); - } + throw new PluginConfigurationError("No Single Plugin configured for interface \""+iname+"\""); } - - + // cache of config data for Sequence Plugins; format its // -> [ .. ] (value is Array) private static Map sequenceConfig = new HashMap(); @@ -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. + *

+ * 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 null 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. = @@ -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 anonymousInstanceCache = new HashMap(); // 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 namedInstanceCache = new HashMap(); // 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. = = , [,] \ // = , [ ... ] - 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. = , .. - 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 null 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 null 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. + *

+ * 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 result = new ArrayList(); @@ -603,13 +694,22 @@ public class PluginManager { try { - configureNamedPlugin(iname); + configureNamedPlugin(null, iname); } catch (ClassNotFoundException ce) { // bogus classname should be old news by now. } } + + // 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