Added the ability to inherit up the classpath when loading a properties
file. This allows one to stick a properties file earlier in the classpath that will override values in the properties file (with the same path) that shows up later in the classpath. git-svn-id: https://samskivert.googlecode.com/svn/trunk@222 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: Config.java,v 1.3 2001/07/21 00:50:28 shaper Exp $
|
||||
// $Id: Config.java,v 1.4 2001/08/08 23:46:00 mdb Exp $
|
||||
|
||||
package com.samskivert.util;
|
||||
|
||||
@@ -43,11 +43,14 @@ public class Config
|
||||
* somewhere in the classpath. For example: <code>foo/bar/baz</code>
|
||||
* would indicate a file named "foo/bar/baz.properties" living in the
|
||||
* classpath.
|
||||
* @param inherit if true, the properties file will be loaded using
|
||||
* {@link ConfigUtil#loadInheritedProperties} rather than {@link
|
||||
* ConfigUtil#loadProperties}.
|
||||
*
|
||||
* @exception IOException thrown if an error occurrs loading the
|
||||
* properties file (like it doesn't exist or cannot be accessed).
|
||||
*/
|
||||
public void bindProperties (String name, String path)
|
||||
public void bindProperties (String name, String path, boolean inherit)
|
||||
throws IOException
|
||||
{
|
||||
// append the file suffix onto the path
|
||||
@@ -57,10 +60,22 @@ public class Config
|
||||
if (props == null) {
|
||||
throw new IOException("Unable to load properties file: " + path);
|
||||
}
|
||||
// put it into the hashtable with the specified name
|
||||
// bind the properties instance
|
||||
_props.put(name, props);
|
||||
}
|
||||
|
||||
/**
|
||||
* A backwards compatibility method that does not use inherited
|
||||
* properties loading.
|
||||
*
|
||||
* @see #bindProperties(String,String,boolean)
|
||||
*/
|
||||
public void bindProperties (String name, String path)
|
||||
throws IOException
|
||||
{
|
||||
bindProperties(name, path, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches and returns the value for the specified configuration
|
||||
* property. If the value is not specified in the associated
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
//
|
||||
// $Id: ConfigUtil.java,v 1.2 2001/02/15 01:15:02 mdb Exp $
|
||||
// $Id: ConfigUtil.java,v 1.3 2001/08/08 23:46:00 mdb Exp $
|
||||
|
||||
package com.samskivert.util;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.samskivert.Log;
|
||||
|
||||
/**
|
||||
* The config util class provides routines for loading configuration
|
||||
* information out of a file that lives somewhere in the classpath.
|
||||
@@ -26,7 +31,7 @@ public class ConfigUtil
|
||||
*
|
||||
* @param path The path to the properties file, relative to the root
|
||||
* of the classpath entry from which it will be loaded
|
||||
* (e.g. /conf/foo.properties or perhaps just bar.properties).
|
||||
* (e.g. <code>/conf/foo.properties</code>).
|
||||
*
|
||||
* @return A properties object loaded with the contents of the
|
||||
* specified file if the file could be found, null otherwise.
|
||||
@@ -38,25 +43,16 @@ public class ConfigUtil
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a properties file from the named file that exists somewhere
|
||||
* in the classpath. A full path should be supplied, but variations
|
||||
* including and not including a leading slash will be used because
|
||||
* JVMs differ on their opinion of whether this is necessary.
|
||||
* Like the other version of {@link #loadProperties(String)}
|
||||
* but this one uses the supplied class loader rather than the class
|
||||
* loader used to load the <code>ConfigUtil</code> class.
|
||||
*
|
||||
* <p> The supplied classloader is searched first, followed by the
|
||||
* system classloader.
|
||||
*
|
||||
* @param path The path to the properties file, relative to the root
|
||||
* of the classpath entry from which it will be loaded
|
||||
* (e.g. /conf/foo.properties or perhaps just bar.properties).
|
||||
*
|
||||
* @return A properties object loaded with the contents of the
|
||||
* specified file if the file could be found, null otherwise.
|
||||
* @see #loadProperties(String)
|
||||
*/
|
||||
public static Properties loadProperties (String name, ClassLoader loader)
|
||||
public static Properties loadProperties (String path, ClassLoader loader)
|
||||
throws IOException
|
||||
{
|
||||
InputStream in = getStream(name, loader);
|
||||
InputStream in = getStream(path, loader);
|
||||
Properties props = null;
|
||||
|
||||
if (in != null) {
|
||||
@@ -67,6 +63,90 @@ public class ConfigUtil
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a properties instance by combining properties files loaded
|
||||
* using the specified classpath-relative property file path. A
|
||||
* leading slash should be supplied, but variations including and not
|
||||
* including a leading slash will be used because JVMs differ on their
|
||||
* opinion of whether this is necessary.
|
||||
*
|
||||
* <p> The inheritance works like so: the file will be searched for in
|
||||
* the classpath from farthest to nearest. Near and far in the
|
||||
* classpath are defined by the class loading search order. Normal
|
||||
* class loading searches from nearest to farthest. Beginning with the
|
||||
* farthest copy of the properties file, sucessively nearer copies
|
||||
* will be overlaid onto those properties to achieve a sort of
|
||||
* inheritance. Properties specified in nearer versions of the file
|
||||
* will override those in farther versions of the file, but properties
|
||||
* not specified in nearer versions will be "inherited" from the
|
||||
* farther versions. Using this mechanism, a standard set of defaults
|
||||
* can be provided and users need only place a properties file with
|
||||
* their preferred overrides somewhere nearer in the classpath to have
|
||||
* those overrides properly combined with the original
|
||||
* defaults. Because the entire classpath is searched, this process
|
||||
* can cascade up through a set of properties files and provide a
|
||||
* powerful mechanism for inheriting configuration information.
|
||||
*
|
||||
* <p> The classloader that loaded the <code>ConfigUtil</code> class
|
||||
* is searched first, followed by the system classpath. If you wish to
|
||||
* provide an additional classloader, use the version of this function
|
||||
* that takes a classloader as an argument.
|
||||
*
|
||||
* @param path The path to the properties file, relative to the root
|
||||
* of the classpath entries from which it will be loaded
|
||||
* (e.g. <code>/conf/foo.properties</code>).
|
||||
*
|
||||
* @return A properties object loaded with the contents of the
|
||||
* specified file if the file could be found, null otherwise.
|
||||
*/
|
||||
public static Properties loadInheritedProperties (String path)
|
||||
throws IOException
|
||||
{
|
||||
return loadInheritedProperties(
|
||||
path, ConfigUtil.class.getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the other version of {@link #loadInheritedProperties(String)}
|
||||
* but this one uses the supplied class loader rather than the class
|
||||
* loader used to load the <code>ConfigUtil</code> class.
|
||||
*
|
||||
* @see #loadInheritedProperties(String)
|
||||
*/
|
||||
public static Properties loadInheritedProperties (
|
||||
String path, ClassLoader loader)
|
||||
throws IOException
|
||||
{
|
||||
// first look for the files in the supplied class loader
|
||||
Enumeration enum = getResources(path, loader);
|
||||
if (!enum.hasMoreElements()) {
|
||||
// if we couldn't find anything there, try the system class
|
||||
// loader (but only if that's not where we were already
|
||||
// looking)
|
||||
ClassLoader sysloader = ClassLoader.getSystemClassLoader();
|
||||
if (sysloader != loader) {
|
||||
enum = getResources(path, sysloader);
|
||||
}
|
||||
}
|
||||
|
||||
// we need to process the resources in reverse order, so we put
|
||||
// them all into an array first
|
||||
ArrayList rsrcs = new ArrayList();
|
||||
while (enum.hasMoreElements()) {
|
||||
rsrcs.add(enum.nextElement());
|
||||
}
|
||||
|
||||
// now load each file in turn into our properties object
|
||||
Properties props = new Properties();
|
||||
for (int i = rsrcs.size()-1; i >= 0; i--) {
|
||||
URL rurl = (URL)rsrcs.get(i);
|
||||
InputStream in = rurl.openStream();
|
||||
props.load(in);
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an input stream referencing a file that exists somewhere in
|
||||
* the classpath. A full path (relative to the classpath directories)
|
||||
@@ -81,8 +161,8 @@ public class ConfigUtil
|
||||
*
|
||||
* @param path The path to the file, relative to the root of the
|
||||
* classpath directory from which it will be loaded
|
||||
* (e.g. /conf/foo.gif or perhaps just bar.gif if the file is at the
|
||||
* top level).
|
||||
* (e.g. <code>/conf/foo.gif</code> or perhaps just
|
||||
* <code>/bar.gif</code> if the file is at the top level).
|
||||
*/
|
||||
public static InputStream getStream (String path)
|
||||
{
|
||||
@@ -101,32 +181,62 @@ public class ConfigUtil
|
||||
*
|
||||
* @param path The path to the file, relative to the root of the
|
||||
* classpath directory from which it will be loaded
|
||||
* (e.g. /conf/foo.gif or perhaps just bar.gif if the file is at the
|
||||
* top level).
|
||||
* (e.g. <code>/conf/foo.gif</code> or perhaps just
|
||||
* <code>/bar.gif</code> if the file is at the top level).
|
||||
*/
|
||||
public static InputStream getStream (String path, ClassLoader loader)
|
||||
{
|
||||
// first try the supplied class loader
|
||||
InputStream in = getResourceAsStream(path, loader);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
|
||||
// if that didn't work, try the system class loader (but only if
|
||||
// it's different from the class loader we just tried)
|
||||
ClassLoader sysloader = ClassLoader.getSystemClassLoader();
|
||||
if (sysloader != loader) {
|
||||
return getResourceAsStream(path, loader);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static InputStream getResourceAsStream (
|
||||
String path, ClassLoader loader)
|
||||
{
|
||||
// make sure the class loader isn't null
|
||||
if (loader == null) {
|
||||
// Log.debug("No loader for get resource request " +
|
||||
// "[path=" + path + "].");
|
||||
return null;
|
||||
}
|
||||
// try the path as is
|
||||
InputStream in = loader.getResourceAsStream(path);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
|
||||
// try toggling the leading slash
|
||||
String apath = togglePath(path);
|
||||
in = loader.getResourceAsStream(apath);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
return loader.getResourceAsStream(togglePath(path));
|
||||
}
|
||||
|
||||
// if that didn't work, try the system classloader
|
||||
in = Class.class.getResourceAsStream(path);
|
||||
if (in != null) {
|
||||
return in;
|
||||
protected static Enumeration getResources (
|
||||
String path, ClassLoader loader)
|
||||
throws IOException
|
||||
{
|
||||
// make sure the class loader isn't null
|
||||
if (loader == null) {
|
||||
// Log.debug("No loader for get resource request " +
|
||||
// "[path=" + path + "].");
|
||||
return null;
|
||||
}
|
||||
// try the path as is
|
||||
Enumeration enum = loader.getResources(path);
|
||||
if (enum.hasMoreElements()) {
|
||||
return enum;
|
||||
}
|
||||
|
||||
// help us obi wan, you're our only hope
|
||||
return Class.class.getResourceAsStream(apath);
|
||||
// try toggling the leading slash
|
||||
return loader.getResources(togglePath(path));
|
||||
}
|
||||
|
||||
protected static String togglePath (String path)
|
||||
@@ -137,4 +247,18 @@ public class ConfigUtil
|
||||
return "/" + path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test driver.
|
||||
*/
|
||||
public static void main (String[] args)
|
||||
{
|
||||
try {
|
||||
String path = "/com/samskivert/util/test.properties";
|
||||
Properties props = loadInheritedProperties(path);
|
||||
System.out.println(props);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user