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;
|
package com.samskivert.util;
|
||||||
|
|
||||||
@@ -43,11 +43,14 @@ public class Config
|
|||||||
* somewhere in the classpath. For example: <code>foo/bar/baz</code>
|
* somewhere in the classpath. For example: <code>foo/bar/baz</code>
|
||||||
* would indicate a file named "foo/bar/baz.properties" living in the
|
* would indicate a file named "foo/bar/baz.properties" living in the
|
||||||
* classpath.
|
* 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
|
* @exception IOException thrown if an error occurrs loading the
|
||||||
* properties file (like it doesn't exist or cannot be accessed).
|
* 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
|
throws IOException
|
||||||
{
|
{
|
||||||
// append the file suffix onto the path
|
// append the file suffix onto the path
|
||||||
@@ -57,10 +60,22 @@ public class Config
|
|||||||
if (props == null) {
|
if (props == null) {
|
||||||
throw new IOException("Unable to load properties file: " + path);
|
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);
|
_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
|
* Fetches and returns the value for the specified configuration
|
||||||
* property. If the value is not specified in the associated
|
* 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;
|
package com.samskivert.util;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.samskivert.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The config util class provides routines for loading configuration
|
* The config util class provides routines for loading configuration
|
||||||
* information out of a file that lives somewhere in the classpath.
|
* 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
|
* @param path The path to the properties file, relative to the root
|
||||||
* of the classpath entry from which it will be loaded
|
* 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
|
* @return A properties object loaded with the contents of the
|
||||||
* specified file if the file could be found, null otherwise.
|
* 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
|
* Like the other version of {@link #loadProperties(String)}
|
||||||
* in the classpath. A full path should be supplied, but variations
|
* but this one uses the supplied class loader rather than the class
|
||||||
* including and not including a leading slash will be used because
|
* loader used to load the <code>ConfigUtil</code> class.
|
||||||
* JVMs differ on their opinion of whether this is necessary.
|
|
||||||
*
|
*
|
||||||
* <p> The supplied classloader is searched first, followed by the
|
* @see #loadProperties(String)
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
public static Properties loadProperties (String name, ClassLoader loader)
|
public static Properties loadProperties (String path, ClassLoader loader)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
InputStream in = getStream(name, loader);
|
InputStream in = getStream(path, loader);
|
||||||
Properties props = null;
|
Properties props = null;
|
||||||
|
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
@@ -67,6 +63,90 @@ public class ConfigUtil
|
|||||||
return props;
|
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
|
* Returns an input stream referencing a file that exists somewhere in
|
||||||
* the classpath. A full path (relative to the classpath directories)
|
* 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
|
* @param path The path to the file, relative to the root of the
|
||||||
* classpath directory from which it will be loaded
|
* classpath directory from which it will be loaded
|
||||||
* (e.g. /conf/foo.gif or perhaps just bar.gif if the file is at the
|
* (e.g. <code>/conf/foo.gif</code> or perhaps just
|
||||||
* top level).
|
* <code>/bar.gif</code> if the file is at the top level).
|
||||||
*/
|
*/
|
||||||
public static InputStream getStream (String path)
|
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
|
* @param path The path to the file, relative to the root of the
|
||||||
* classpath directory from which it will be loaded
|
* classpath directory from which it will be loaded
|
||||||
* (e.g. /conf/foo.gif or perhaps just bar.gif if the file is at the
|
* (e.g. <code>/conf/foo.gif</code> or perhaps just
|
||||||
* top level).
|
* <code>/bar.gif</code> if the file is at the top level).
|
||||||
*/
|
*/
|
||||||
public static InputStream getStream (String path, ClassLoader loader)
|
public static InputStream getStream (String path, ClassLoader loader)
|
||||||
{
|
{
|
||||||
// first try the supplied class 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);
|
InputStream in = loader.getResourceAsStream(path);
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try toggling the leading slash
|
// try toggling the leading slash
|
||||||
String apath = togglePath(path);
|
return loader.getResourceAsStream(togglePath(path));
|
||||||
in = loader.getResourceAsStream(apath);
|
}
|
||||||
if (in != null) {
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if that didn't work, try the system classloader
|
protected static Enumeration getResources (
|
||||||
in = Class.class.getResourceAsStream(path);
|
String path, ClassLoader loader)
|
||||||
if (in != null) {
|
throws IOException
|
||||||
return in;
|
{
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
// try toggling the leading slash
|
||||||
// help us obi wan, you're our only hope
|
return loader.getResources(togglePath(path));
|
||||||
return Class.class.getResourceAsStream(apath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static String togglePath (String path)
|
protected static String togglePath (String path)
|
||||||
@@ -137,4 +247,18 @@ public class ConfigUtil
|
|||||||
return "/" + path;
|
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