From 804f98de22660e5bdbfb5c24e565994f3bf492c4 Mon Sep 17 00:00:00 2001 From: mdb Date: Thu, 12 Jul 2001 02:44:34 +0000 Subject: [PATCH] Created a configuration management object that provides access to typed config values retrieved from properties files that live in the classpath. Also modified build system to copy properties files from the classpath into the target directory so that they are properly available. git-svn-id: https://samskivert.googlecode.com/svn/trunk@165 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- projects/samskivert/build.xml | 3 + .../src/java/com/samskivert/util/Config.java | 244 ++++++++++++++++++ .../tests/rsrc/util/test.properties | 10 + 3 files changed, 257 insertions(+) create mode 100644 projects/samskivert/src/java/com/samskivert/util/Config.java create mode 100644 projects/samskivert/tests/rsrc/util/test.properties diff --git a/projects/samskivert/build.xml b/projects/samskivert/build.xml index 3071e228..c28e4042 100644 --- a/projects/samskivert/build.xml +++ b/projects/samskivert/build.xml @@ -15,6 +15,9 @@ + + + diff --git a/projects/samskivert/src/java/com/samskivert/util/Config.java b/projects/samskivert/src/java/com/samskivert/util/Config.java new file mode 100644 index 00000000..1fcf55d8 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/util/Config.java @@ -0,0 +1,244 @@ +// +// $Id: Config.java,v 1.1 2001/07/12 02:44:34 mdb Exp $ + +package com.samskivert.util; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Properties; + +import com.samskivert.Log; + +/** + * The config class provides a unified interaface to application + * configuration information. It takes care of loading properties files + * from locations in the classpath and binding the properties in those + * files into the global config namespace. It also provides access to more + * datatypes than simply strings, handling the parsing of ints as well as + * int arrays and string arrays. + * + *

An application should construct a single instance of + * Config and use it to access all of its configuration + * information. + */ +public class Config +{ + /** + * Constructs a new config object which can be used immediately by + * binding properties files into the namespace and subsequently + * requesting values. + */ + public Config () + { + } + + /** + * Binds the specified properties file into the namespace with the + * specified name. If the properties file in question contains a + * property of the name foo.bar and the file is bound + * into the namespace under baz, then that property would + * be accessed as baz.foo.bar. + * + * @param name the root name for all properties in this file. + * @param path the path to the properties file which must live + * somewhere in the classpath. For example: foo/bar/baz + * would indicate a file named "foo/bar/baz.properties" living in the + * classpath. + * + * @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) + throws IOException + { + // append the file suffix onto the path + path += PROPS_SUFFIX; + // load the properties file + Properties props = ConfigUtil.loadProperties(path); + if (props == null) { + throw new IOException("Unable to load properties file: " + path); + } + // put it into the hashtable with the specified name + _props.put(name, props); + } + + /** + * Fetches and returns the value for the specified configuration + * property. If the value is not specified in the associated + * properties file, the supplied default value is returned instead. If + * the property specified in the file is poorly formatted (not and + * integer, not in proper array specification), a warning message will + * be logged and the default value will be returned. + * + * @param the fully qualified name of the property (fully qualified + * meaning that it contains the namespace identifier as well), for + * example: foo.bar.baz. + * @param defval the value to return if the property is not specified + * in the config file. + * + * @return the value of the requested property. + */ + public int getValue (String name, int defval) + { + String val = resolveProperty(name); + + // if it's not specified, we return the default + if (val == null) { + return defval; + } + + // otherwise parse it into an integer + try { + return Integer.parseInt(val); + } catch (NumberFormatException nfe) { + Log.warning("Malformed integer property [fqn=" + name + + ", value=" + val + "]."); + return defval; + } + } + + /** + * Fetches and returns the value for the specified configuration + * property. If the value is not specified in the associated + * properties file, the supplied default value is returned instead. + * + * @param the fully qualified name of the property (fully qualified + * meaning that it contains the namespace identifier as well), for + * example: foo.bar.baz. + * @param defval the value to return if the property is not specified + * in the config file. + * + * @return the value of the requested property. + */ + public String getValue (String name, String defval) + { + String val = resolveProperty(name); + // if it's not specified, we return the default + return (val == null) ? defval : val; + } + + /** + * Fetches and returns the value for the specified configuration + * property. If the value is not specified in the associated + * properties file, the supplied default value is returned instead. If + * the property specified in the file is poorly formatted (not and + * integer, not in proper array specification), a warning message will + * be logged and the default value will be returned. + * + * @param the fully qualified name of the property (fully qualified + * meaning that it contains the namespace identifier as well), for + * example: foo.bar.baz. + * @param defval the value to return if the property is not specified + * in the config file. + * + * @return the value of the requested property. + */ + public int[] getValue (String name, int[] defval) + { + String val = resolveProperty(name); + + // if it's not specified, we return the default + if (val == null) { + return defval; + } + + // otherwise parse it into an array of ints + int[] result = StringUtil.parseIntArray(val); + if (result == null) { + Log.warning("Malformed int array property [fqn=" + name + + ", value=" + val + "]."); + return defval; + } + + return result; + } + + /** + * Fetches and returns the value for the specified configuration + * property. If the value is not specified in the associated + * properties file, the supplied default value is returned instead. If + * the property specified in the file is poorly formatted (not and + * integer, not in proper array specification), a warning message will + * be logged and the default value will be returned. + * + * @param the fully qualified name of the property (fully qualified + * meaning that it contains the namespace identifier as well), for + * example: foo.bar.baz. + * @param defval the value to return if the property is not specified + * in the config file. + * + * @return the value of the requested property. + */ + public String[] getValue (String name, String[] defval) + { + String val = resolveProperty(name); + + // if it's not specified, we return the default + if (val == null) { + return defval; + } + + // otherwise parse it into an array of strings + String[] result = StringUtil.parseStringArray(val); + if (result == null) { + Log.warning("Malformed string array property [fqn=" + name + + ", value=" + val + "]."); + return defval; + } + + return result; + } + + protected String resolveProperty (String name) + { + int didx = name.indexOf("."); + if (didx == -1) { + Log.warning("Invalid fully qualified property name " + + "[name=" + name + "]."); + return null; + } + + String id = name.substring(0, didx); + String key = name.substring(didx+1); + + Properties props = (Properties)_props.get(id); + if (props == null) { + Log.warning("No property file bound to top-level name " + + "[name=" + id + ", key=" + key + "]."); + return null; + } + + return props.getProperty(key); + } + + public static void main (String[] args) + { + Config config = new Config(); + try { + config.bindProperties("test", "com/samskivert/util/test"); + + System.out.println("test.prop1: " + + config.getValue("test.prop1", 1)); + System.out.println("test.prop2: " + + config.getValue("test.prop2", "two")); + + int[] ival = new int[] { 1, 2, 3 }; + ival = config.getValue("test.prop3", ival); + System.out.println("test.prop3: " + StringUtil.toString(ival)); + + String[] sval = new String[] { "one", "two", "three" }; + sval = config.getValue("test.prop4", sval); + System.out.println("test.prop4: " + StringUtil.toString(sval)); + + System.out.println("test.prop5: " + + config.getValue("test.prop5", "undefined")); + + } catch (IOException ioe) { + ioe.printStackTrace(System.err); + } + } + + protected Hashtable _props = new Hashtable(); + + protected static final String PROPS_SUFFIX = ".properties"; +} diff --git a/projects/samskivert/tests/rsrc/util/test.properties b/projects/samskivert/tests/rsrc/util/test.properties new file mode 100644 index 00000000..0252ea9c --- /dev/null +++ b/projects/samskivert/tests/rsrc/util/test.properties @@ -0,0 +1,10 @@ +# +# $Id: test.properties,v 1.1 2001/07/12 02:44:34 mdb Exp $ +# +# A test properties file + +prop1 = 25 +prop2 = twenty five +prop3 = 9, 8, 7, 6 +prop4 = one, two, three,, and a half, four +# prop5 = not defined