git-svn-id: https://samskivert.googlecode.com/svn/trunk@2043 6335cc39-0255-0410-8fd6-9bcaacd3b74c

This commit is contained in:
mdb
2007-01-31 00:41:25 +00:00
parent f8003a05c8
commit f406bc46c6
6 changed files with 470 additions and 491 deletions
@@ -31,32 +31,28 @@ import javax.swing.Scrollable;
import com.samskivert.Log;
import com.samskivert.util.ComparableArrayList;
import com.samskivert.util.Config;
import com.samskivert.util.PrefsConfig;
import com.samskivert.util.DebugChords;
import com.samskivert.util.ListUtil;
import com.samskivert.util.StringUtil;
/**
* Provides a service where named variables can be registered as
* adjustable by the developer at runtime. Generally a special key is
* configured (via {@link DebugChords}) to pop up the adjustable variables
* interface which can then be used to toggle booleans, change integer
* values and generally adjust debugging and tuning parameters. This is
* not meant to be an interface for end-user configurable parameters, but
* to allow the developer to tweak runtime parameters more easily.
* Provides a service where named variables can be registered as adjustable by the developer at
* runtime. Generally a special key is configured (via {@link DebugChords}) to pop up the
* adjustable variables interface which can then be used to toggle booleans, change integer values
* and generally adjust debugging and tuning parameters. This is not meant to be an interface for
* end-user configurable parameters, but to allow the developer to tweak runtime parameters more
* easily.
*
* <p> Adjustments are bound to a {@link Config} property which can be
* changed through the config interface or through the bound runtime
* adjust.
* <p> Adjustments are bound to a {@link PrefsConfig} property which can be changed through the
* config interface or through the bound runtime adjust.
*
* <p> <em>Note:</em> adjusts are meant to be arranged in a two level
* hierarchy. An adjust's name, therefore, should be of the form:
* <code>library.package.adjustment</code>. The <code>package</code>
* component can consist of multiple words joined with a period, but the
* <code>library</code> will always be the first word before the first
* period and the <code>adjustment</code> always the last word after the
* final period. This is mainly only important for organizing the runtime
* adjustment editing interface.
* <p> <em>Note:</em> adjusts are meant to be arranged in a two level hierarchy. An adjust's name,
* therefore, should be of the form: <code>library.package.adjustment</code>. The
* <code>package</code> component can consist of multiple words joined with a period, but the
* <code>library</code> will always be the first word before the first period and the
* <code>adjustment</code> always the last word after the final period. This is mainly only
* important for organizing the runtime adjustment editing interface.
*/
public class RuntimeAdjust
{
@@ -147,8 +143,7 @@ public class RuntimeAdjust
public static class BooleanAdjust extends Adjust
implements ActionListener
{
public BooleanAdjust (String descrip, String name,
Config config, boolean defval)
public BooleanAdjust (String descrip, String name, PrefsConfig config, boolean defval)
{
super(descrip, name, config);
_value = _config.getValue(_name, defval);
@@ -197,8 +192,7 @@ public class RuntimeAdjust
/** Provides runtime adjustable integer variables. */
public static class IntAdjust extends TextFieldAdjust
{
public IntAdjust (String descrip, String name,
Config config, int defval)
public IntAdjust (String descrip, String name, PrefsConfig config, int defval)
{
super(descrip, name, config);
_value = _config.getValue(_name, defval);
@@ -251,8 +245,8 @@ public class RuntimeAdjust
public static class EnumAdjust extends Adjust
implements ActionListener
{
public EnumAdjust (String descrip, String name,
Config config, String[] values, String defval)
public EnumAdjust (String descrip, String name, PrefsConfig config,
String[] values, String defval)
{
super(descrip, name, config);
_values = values;
@@ -310,9 +304,8 @@ public class RuntimeAdjust
public static class FileAdjust extends Adjust
implements ActionListener
{
public FileAdjust (String descrip, String name,
Config config, boolean directoriesOnly,
String defval)
public FileAdjust (String descrip, String name, PrefsConfig config,
boolean directoriesOnly, String defval)
{
super(descrip, name, config);
_value = _config.getValue(_name, defval);
@@ -431,7 +424,7 @@ public class RuntimeAdjust
protected abstract static class TextFieldAdjust extends Adjust
implements ActionListener, FocusListener
{
public TextFieldAdjust (String descrip, String name, Config config)
public TextFieldAdjust (String descrip, String name, PrefsConfig config)
{
super(descrip, name, config);
}
@@ -464,7 +457,7 @@ public class RuntimeAdjust
protected abstract static class Adjust
implements PropertyChangeListener, Comparable<Adjust>
{
public Adjust (String descrip, String name, Config config)
public Adjust (String descrip, String name, PrefsConfig config)
{
_name = name;
_descrip = descrip;
@@ -550,10 +543,9 @@ public class RuntimeAdjust
}
protected String _name, _descrip;
protected Config _config;
protected PrefsConfig _config;
protected JPanel _editor;
}
protected static ComparableArrayList<Adjust> _adjusts =
new ComparableArrayList<Adjust>();
protected static ComparableArrayList<Adjust> _adjusts = new ComparableArrayList<Adjust>();
}
@@ -9,7 +9,7 @@ import javax.swing.JComponent;
import javax.swing.JFrame;
import com.samskivert.swing.RuntimeAdjust;
import com.samskivert.util.Config;
import com.samskivert.util.PrefsConfig;
/**
* Does something extraordinary.
@@ -18,7 +18,7 @@ public class AdjustTestApp
{
public static void main (String[] args)
{
Config config = new Config("test");
PrefsConfig config = new PrefsConfig("test");
new RuntimeAdjust.IntAdjust(
"This is a test adjustment. It is nice.",
"samskivert.test.int_adjust1", config, 5);
@@ -16,7 +16,7 @@ import javax.swing.JToggleButton;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import com.samskivert.util.Config;
import com.samskivert.util.PrefsConfig;
import com.samskivert.util.IntListUtil;
/**
@@ -25,8 +25,8 @@ import com.samskivert.util.IntListUtil;
public class ButtonUtil
{
/**
* Set the specified button such that it alternates between being
* selected and not whenever it is pushed.
* Set the specified button such that it alternates between being selected and not whenever it
* is pushed.
*/
public static synchronized void setToggling (AbstractButton b)
{
@@ -44,28 +44,25 @@ public class ButtonUtil
}
/**
* Binds the supplied button to the named boolean property in the
* supplied config repository. When the button is pressed, it will
* update the config property and when the config property is changed
* (by the button or by other means) it will update the selected state
* of the button. When the button is made non-visible, it will be
* unbound to the config's property and rebound again if it is once
* again visible.
* Binds the supplied button to the named boolean property in the supplied config repository.
* When the button is pressed, it will update the config property and when the config property
* is changed (by the button or by other means) it will update the selected state of the
* button. When the button is made non-visible, it will be unbound to the config's property and
* rebound again if it is once again visible.
*/
public static void bindToProperty (
String property, Config config, AbstractButton button, boolean defval)
String property, PrefsConfig config, AbstractButton button, boolean defval)
{
// create a config binding which will take care of everything
new ButtonConfigBinding(property, config, button, defval);
}
/**
* Configure the specified button to cause the specified
* property to cycle through the specified values whenever the button is
* pressed.
* Configure the specified button to cause the specified property to cycle through the
* specified values whenever the button is pressed.
*/
public static ActionListener cycleToProperty (
final String property, final Config config, AbstractButton button,
final String property, final PrefsConfig config, AbstractButton button,
final int[] values)
{
ActionListener al = new ActionListener() {
@@ -87,7 +84,7 @@ public class ButtonUtil
protected static class ButtonConfigBinding
implements AncestorListener, PropertyChangeListener, ItemListener
{
public ButtonConfigBinding (String property, Config config,
public ButtonConfigBinding (String property, PrefsConfig config,
AbstractButton button, boolean defval)
{
_property = property;
@@ -136,7 +133,7 @@ public class ButtonUtil
}
protected String _property;
protected Config _config;
protected PrefsConfig _config;
protected AbstractButton _button;
protected boolean _defval;
}
+101 -435
View File
@@ -3,7 +3,7 @@
//
// samskivert library - useful routines for java programs
// Copyright (C) 2001 Michael Bayne
//
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
@@ -20,12 +20,6 @@
package com.samskivert.util;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -34,22 +28,16 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import com.samskivert.Log;
/**
* The config class provides a unified interaface to application
* configuration information. It takes care of loading properties files
* (done via the classpath) and allows for overriding and inheriting of
* properties values (see {@link ConfigUtil#loadInheritedProperties}).
* The config class provides a unified interaface to application configuration information. It
* takes care of loading properties files (done via the classpath) and allows for overriding and
* inheriting of properties values (see {@link ConfigUtil#loadInheritedProperties}).
*
* <p> A common pattern is to create, for each package that shares
* configuration information, a singleton class containing a config object
* that is configured to load its data from a single configuration
* file. For example:
* <p> A common pattern is to create, for each package that shares configuration information, a
* singleton class containing a config object that is configured to load its data from a single
* configuration file. For example:
*
* <pre>
* public class FooConfig
@@ -60,9 +48,8 @@ import com.samskivert.Log;
* }
* </pre>
*
* which would look for <code>com/fribitz/foo.properties</code> in the
* classpath and serve up those configuration values when requests were
* made from <code>FooConfig.config</code>. For example:
* which would look for <code>com/fribitz/foo.properties</code> in the classpath and serve up those
* configuration values when requests were made from <code>FooConfig.config</code>. For example:
*
* <pre>
* int fiddles = FooConfig.config.getValue(FooConfig.FIDDLES, 0);
@@ -71,8 +58,7 @@ import com.samskivert.Log;
* }
* </pre>
*
* An even better approach involves creating accessors for all defined
* configuration properties:
* An even better approach involves creating accessors for all defined configuration properties:
*
* <pre>
* public class FooConfig
@@ -90,23 +76,16 @@ import com.samskivert.Log;
* }
* </pre>
*
* This allows the default value for <code>fiddles</code> to be specified
* in one place and simplifies life for the caller who can now simply
* request <code>FooConfig.getFiddles()</code>.
* This allows the default value for <code>fiddles</code> to be specified in one place and
* simplifies life for the caller who can now simply request <code>FooConfig.getFiddles()</code>.
*
* <p> The config class allows one to override configuration values
* persistently, using the standard Java {@link Preferences} facilities to
* maintain the overridden values. If a property is {@link #setValue}d in
* a configuration object, it will remain overridden in between
* invocations of the application (leveraging the benefits of the
* pluggable preferences backends provided by the standard Java
* preferences facilities).
* @see PrefsConfig
*/
public class Config
{
/**
* Constructs a new config object which will obtain configuration
* information from the specified properties bundle.
* Constructs a new config object which will obtain configuration information from the
* specified properties bundle.
*/
public Config (String path)
{
@@ -121,119 +100,59 @@ public class Config
ConfigUtil.loadInheritedProperties(ppath, _props);
} catch (FileNotFoundException fnfe) {
Log.debug("No properties file found to back config " +
"[path=" + path + "].");
Log.debug("No properties file found to back config [path=" + path + "].");
} catch (IOException ioe) {
Log.warning("Unable to load configuration [path=" + path +
", ioe=" + ioe + "].");
}
// get a handle on the preferences instance that we'll use to
// override values in the properties file
try {
_prefs = Preferences.userRoot().node(path);
} catch (AccessControlException ace) {
// security manager won't let us access prefs, no problem!
Log.info("Can't access preferences [path=" + path + "].");
_prefs = new NullPreferences();
Log.warning("Unable to load configuration [path=" + path + ", ioe=" + ioe + "].");
}
}
/**
* Constructs a config object which will obtain information from the
* supplied properties, rooted at the specified path in the
* preferences hieriarchy.
* Constructs a config object which will obtain information from the supplied properties.
*/
public Config (final String path, Properties props)
public Config (String path, Properties props)
{
_props = props;
try {
_prefs = Preferences.userRoot().node(path);
} catch (AccessControlException ace) {
// security manager won't let us access prefs, no problem!
Log.info("Can't access preferences [path=" + path + "].");
_prefs = new NullPreferences();
}
}
/**
* 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.
* 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 name name of the property.
* @param defval the value to return if the property is not specified
* in the config file.
* @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)
{
return _prefs.getInt(name, getDefValue(name, defval));
}
/**
* Returns the value specified in the properties override file.
*/
protected int getDefValue (String name, int defval)
{
String val = _props.getProperty(name);
if (val != null) {
try {
// handles base 10, hex values, etc.
return Integer.decode(val).intValue();
return Integer.decode(val).intValue(); // handles base 10, hex values, etc.
} catch (NumberFormatException nfe) {
Log.warning("Malformed integer property [name=" + name +
", value=" + val + "].");
Log.warning("Malformed integer property [name=" + name + ", value=" + val + "].");
}
}
return defval;
}
/**
* Sets the value of the specified preference, overriding the value
* defined in the configuration files shipped with the application.
*/
public void setValue (String name, int value)
{
Integer oldValue = null;
if (_prefs.get(name, null) != null ||
_props.getProperty(name) != null) {
oldValue = Integer.valueOf(
_prefs.getInt(name, getDefValue(name, 0)));
}
_prefs.putInt(name, value);
_propsup.firePropertyChange(name, oldValue, Integer.valueOf(value));
}
/**
* 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.
* 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 name name of the property.
* @param defval the value to return if the property is not specified
* in the config file.
* @param defval the value to return if the property is not specified in the config file.
*
* @return the value of the requested property.
*/
public long getValue (String name, long defval)
{
return _prefs.getLong(name, getDefValue(name, defval));
}
/**
* Returns the value specified in the properties override file.
*/
protected long getDefValue (String name, long defval)
{
String val = _props.getProperty(name);
if (val != null) {
@@ -248,45 +167,18 @@ public class Config
}
/**
* Sets the value of the specified preference, overriding the value
* defined in the configuration files shipped with the application.
*/
public void setValue (String name, long value)
{
Long oldValue = null;
if (_prefs.get(name, null) != null ||
_props.getProperty(name) != null) {
oldValue = Long.valueOf(
_prefs.getLong(name, getDefValue(name, 0L)));
}
_prefs.putLong(name, value);
_propsup.firePropertyChange(name, oldValue, Long.valueOf(value));
}
/**
* 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.
* 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 name name of the property.
* @param defval the value to return if the property is not specified
* in the config file.
* @param defval the value to return if the property is not specified in the config file.
*
* @return the value of the requested property.
*/
public float getValue (String name, float defval)
{
return _prefs.getFloat(name, getDefValue(name, defval));
}
/**
* Returns the value specified in the properties override file.
*/
protected float getDefValue (String name, float defval)
{
String val = _props.getProperty(name);
if (val != null) {
@@ -301,79 +193,17 @@ public class Config
}
/**
* Sets the value of the specified preference, overriding the value
* defined in the configuration files shipped with the application.
*/
public void setValue (String name, float value)
{
Float oldValue = null;
if (_prefs.get(name, null) != null ||
_props.getProperty(name) != null) {
oldValue = Float.valueOf(
_prefs.getFloat(name, getDefValue(name, 0f)));
}
_prefs.putFloat(name, value);
_propsup.firePropertyChange(name, oldValue, Float.valueOf(value));
}
/**
* 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.
* 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.
* The returned value will be <code>false</code> if the config value is <code>"false"</code>
* (case-insensitive), else the return value will be true.
*
* @param name the name of the property to be fetched.
* @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)
{
// if there is a value, parse it into an integer
String val = _props.getProperty(name);
if (val != null) {
defval = val;
}
// finally look for an overridden value
return _prefs.get(name, defval);
}
/**
* Sets the value of the specified preference, overriding the value
* defined in the configuration files shipped with the application.
*/
public void setValue (String name, String value)
{
String oldValue = getValue(name, (String)null);
_prefs.put(name, value);
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* 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. The returned value will be <code>false</code> if the
* config value is <code>"false"</code> (case-insensitive), else
* the return value will be true.
*
* @param name the name of the property to be fetched.
* @param defval the value to return if the property is not specified
* in the config file.
* @param defval the value to return if the property is not specified in the config file.
*
* @return the value of the requested property.
*/
public boolean getValue (String name, boolean defval)
{
return _prefs.getBoolean(name, getDefValue(name, defval));
}
/**
* Returns the value specified in the properties override file.
*/
protected boolean getDefValue (String name, boolean defval)
{
String val = _props.getProperty(name);
if (val != null) {
@@ -383,41 +213,35 @@ public class Config
}
/**
* Sets the value of the specified preference, overriding the value
* defined in the configuration files shipped with the application.
* 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 name the name of the property to be fetched.
* @param defval the value to return if the property is not specified in the config file.
*
* @return the value of the requested property.
*/
public void setValue (String name, boolean value)
public String getValue (String name, String defval)
{
Boolean oldValue = null;
if (_prefs.get(name, null) != null ||
_props.getProperty(name) != null) {
oldValue = Boolean.valueOf(
_prefs.getBoolean(name, getDefValue(name, false)));
}
_prefs.putBoolean(name, value);
_propsup.firePropertyChange(name, oldValue, Boolean.valueOf(value));
return _props.getProperty(name, 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. 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.
* 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 name the name of the property to be fetched.
* @param defval the value to return if the property is not specified
* in the config file.
* @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)
{
// look up the value in the configuration file and use that to
// look up any overridden value
String val = _prefs.get(name, _props.getProperty(name));
// look up the value in the configuration file and use that to look up any overridden value
String val = getValue(name, (String)null);
int[] result = defval;
// parse it into an array of ints
@@ -434,35 +258,21 @@ public class Config
}
/**
* Sets the value of the specified preference, overriding the value
* defined in the configuration files shipped with the application.
*/
public void setValue (String name, int[] value)
{
int[] oldValue = getValue(name, (int[])null);
_prefs.put(name, StringUtil.toString(value, "", ""));
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* 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.
* 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 name the name of the property to be fetched.
* @param defval the value to return if the property is not specified
* in the config file.
* @param defval the value to return if the property is not specified in the config file.
*
* @return the value of the requested property.
*/
public long[] getValue (String name, long[] defval)
{
// look up the value in the configuration file and use that to
// look up any overridden value
String val = _prefs.get(name, _props.getProperty(name));
// look up the value in the configuration file and use that to look up any overridden value
String val = getValue(name, (String)null);
long[] result = defval;
// parse it into an array of longs
@@ -479,35 +289,21 @@ public class Config
}
/**
* Sets the value of the specified preference, overriding the value
* defined in the configuration files shipped with the application.
*/
public void setValue (String name, long[] value)
{
long[] oldValue = getValue(name, (long[])null);
_prefs.put(name, StringUtil.toString(value, "", ""));
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* 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 a
* floating point value, not in proper array specification), a warning
* message will be logged and the default value will be returned.
* 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 a floating point value, not
* in proper array specification), a warning message will be logged and the default value will
* be returned.
*
* @param name the name of the property to be fetched.
* @param defval the value to return if the property is not specified
* in the config file.
* @param defval the value to return if the property is not specified in the config file.
*
* @return the value of the requested property.
*/
public float[] getValue (String name, float[] defval)
{
// look up the value in the configuration file and use that to
// look up any overridden value
String val = _prefs.get(name, _props.getProperty(name));
// look up the value in the configuration file and use that to look up any overridden value
String val = getValue(name, (String)null);
float[] result = defval;
// parse it into an array of ints
@@ -524,35 +320,21 @@ public class Config
}
/**
* Sets the value of the specified preference, overriding the value
* defined in the configuration files shipped with the application.
*/
public void setValue (String name, float[] value)
{
float[] oldValue = getValue(name, (float[])null);
_prefs.put(name, StringUtil.toString(value, "", ""));
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* 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.
* 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 name the name of the property to be fetched.
* @param defval the value to return if the property is not specified
* in the config file.
* @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)
{
// look up the value in the configuration file and use that to
// look up any overridden value
String val = _prefs.get(name, _props.getProperty(name));
// look up the value in the configuration file and use that to look up any overridden value
String val = getValue(name, (String)null);
String[] result = defval;
// parse it into an array of ints
@@ -569,78 +351,13 @@ public class Config
}
/**
* Sets the value of the specified preference, overriding the value
* defined in the configuration files shipped with the application.
*/
public void setValue (String name, String[] value)
{
String[] oldValue = getValue(name, (String[])null);
_prefs.put(name, StringUtil.joinEscaped(value));
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* Remove any set value for the specified preference.
*/
public void remove (String name)
{
// we treat the old value as a String, I hope that's ok!
String oldValue = getValue(name, (String) null);
_prefs.remove(name);
_propsup.firePropertyChange(name, oldValue, null);
}
/**
* Adds a listener that will be notified whenever any configuration
* properties are changed by a call to one of the <code>set</code>
* methods.
*/
public void addPropertyChangeListener (PropertyChangeListener listener)
{
_propsup.addPropertyChangeListener(listener);
}
/**
* Removes a property change listener previously added via a call to
* {@link #addPropertyChangeListener}.
*/
public void removePropertyChangeListener (PropertyChangeListener listener)
{
_propsup.removePropertyChangeListener(listener);
}
/**
* Adds a listener that will be notified whenever the specified
* configuration property is changed by a call to the appropriate
* <code>set</code> method.
*/
public void addPropertyChangeListener (
String name, PropertyChangeListener listener)
{
_propsup.addPropertyChangeListener(name, listener);
}
/**
* Removes a property change listener previously added via a call to
* {@link #addPropertyChangeListener(String,PropertyChangeListener)}.
*/
public void removePropertyChangeListener (
String name, PropertyChangeListener listener)
{
_propsup.removePropertyChangeListener(name, listener);
}
/**
* Looks up the specified string-valued configuration entry, loads the
* class with that name and instantiates a new instance of that class,
* which is returned.
* Looks up the specified string-valued configuration entry, loads the class with that name and
* instantiates a new instance of that class, which is returned.
*
* @param name the name of the property to be fetched.
* @param defcname the class name to use if the property is not
* specified in the config file.
* @param defcname the class name to use if the property is not specified in the config file.
*
* @exception Exception thrown if any error occurs while loading or
* instantiating the class.
* @exception Exception thrown if any error occurs while loading or instantiating the class.
*/
public Object instantiateValue (String name, String defcname)
throws Exception
@@ -649,10 +366,9 @@ public class Config
}
/**
* Returns a properties object containing all configuration values
* that start with the supplied prefix (plus a trailing "." which will
* be added if it doesn't already exist). The keys in the
* sub-properties will have had the prefix stripped off.
* Returns a properties object containing all configuration values that start with the supplied
* prefix (plus a trailing "." which will be added if it doesn't already exist). The keys in
* the sub-properties will have had the prefix stripped off.
*/
public Properties getSubProperties (String prefix)
{
@@ -662,10 +378,9 @@ public class Config
}
/**
* Fills into the supplied properties object all configuration values
* that start with the supplied prefix (plus a trailing "." which will
* be added if it doesn't already exist). The keys in the
* sub-properties will have had the prefix stripped off.
* Fills into the supplied properties object all configuration values that start with the
* supplied prefix (plus a trailing "." which will be added if it doesn't already exist). The
* keys in the sub-properties will have had the prefix stripped off.
*/
public void getSubProperties (String prefix, Properties target)
{
@@ -690,75 +405,26 @@ public class Config
}
/**
* Returns an iterator that returns all of the configuration keys in
* this config object.
* Returns an iterator that returns all of the configuration keys in this config object.
*/
public Iterator<String> keys ()
{
// what with all the complicated business, we just need to take
// the brute force approach and enumerate everything up front
HashSet<String> matches = new HashSet<String>();
// add the keys provided in the config files
Enumeration defkeys = _props.propertyNames();
while (defkeys.hasMoreElements()) {
matches.add((String)defkeys.nextElement());
}
// then add the overridden keys
try {
String[] keys = _prefs.keys();
for (int i = 0; i < keys.length; i++) {
matches.add(keys[i]);
}
} catch (BackingStoreException bse) {
Log.warning("Unable to enumerate preferences keys " +
"[error=" + bse + "].");
}
enumerateKeys(matches);
return matches.iterator();
}
/** This is used if we don't have security access to the preferences
* implementation that we'd like. */
protected static class NullPreferences extends AbstractPreferences
protected void enumerateKeys (HashSet<String> keys)
{
public NullPreferences () {
super(null, "");
}
protected void putSpi (String key, String value) {
}
protected String getSpi (String key) {
return null;
}
protected void removeSpi (String key) {
}
protected void removeNodeSpi () throws BackingStoreException {
}
protected String[] keysSpi () throws BackingStoreException {
return new String[0];
}
protected String[] childrenNamesSpi () throws BackingStoreException {
return new String[0];
}
protected AbstractPreferences childSpi (String name) {
return null;
}
protected void syncSpi () throws BackingStoreException {
}
protected void flushSpi () throws BackingStoreException {
Enumeration defkeys = _props.propertyNames();
while (defkeys.hasMoreElements()) {
keys.add((String)defkeys.nextElement());
}
}
/** Contains the default configuration information. */
protected Properties _props;
/** Used to maintain configuration overrides. */
protected Preferences _prefs;
/** Used to support our property change mechanism. */
protected PropertyChangeSupport _propsup = new PropertyChangeSupport(this);
/** The file extension used for configuration files. */
protected static final String PROPS_SUFFIX = ".properties";
}
@@ -0,0 +1,325 @@
//
// $Id$
//
// samskivert library - useful routines for java programs
// Copyright (C) 2007 Michael Bayne
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.util;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import com.samskivert.Log;
/**
* Extends the {@link Config} mechanism to allow the modification of configuration values, which
* are persisted using the Java preferences system. If a property is {@link #setValue}d, it will
* remain overridden in between invocations of the application (leveraging the benefits of the
* pluggable preferences backends provided by the standard Java preferences facilities).
*/
public class PrefsConfig extends Config
{
/**
* Constructs a new config object which will obtain configuration information from the
* specified properties bundle.
*/
public PrefsConfig (String path)
{
super(path);
// get a handle on the preferences instance that we'll use to override values in the
// properties file
try {
_prefs = Preferences.userRoot().node(path);
} catch (AccessControlException ace) {
// security manager won't let us access prefs, no problem!
Log.info("Can't access preferences [path=" + path + "].");
_prefs = new NullPreferences();
}
}
/**
* Constructs a config object which will obtain information from the supplied properties,
* rooted at the specified path in the preferences hieriarchy.
*/
public PrefsConfig (String path, Properties props)
{
super(path, props);
try {
_prefs = Preferences.userRoot().node(path);
} catch (AccessControlException ace) {
// security manager won't let us access prefs, no problem!
Log.info("Can't access preferences [path=" + path + "].");
_prefs = new NullPreferences();
}
}
/**
* Sets the value of the specified preference, overriding the value defined in the
* configuration files shipped with the application.
*/
public void setValue (String name, int value)
{
Integer oldValue = null;
if (_prefs.get(name, null) != null || _props.getProperty(name) != null) {
oldValue = Integer.valueOf(_prefs.getInt(name, super.getValue(name, 0)));
}
_prefs.putInt(name, value);
_propsup.firePropertyChange(name, oldValue, Integer.valueOf(value));
}
/**
* Sets the value of the specified preference, overriding the value defined in the
* configuration files shipped with the application.
*/
public void setValue (String name, long value)
{
Long oldValue = null;
if (_prefs.get(name, null) != null || _props.getProperty(name) != null) {
oldValue = Long.valueOf(_prefs.getLong(name, super.getValue(name, 0L)));
}
_prefs.putLong(name, value);
_propsup.firePropertyChange(name, oldValue, Long.valueOf(value));
}
/**
* Sets the value of the specified preference, overriding the value defined in the
* configuration files shipped with the application.
*/
public void setValue (String name, float value)
{
Float oldValue = null;
if (_prefs.get(name, null) != null || _props.getProperty(name) != null) {
oldValue = Float.valueOf(_prefs.getFloat(name, super.getValue(name, 0f)));
}
_prefs.putFloat(name, value);
_propsup.firePropertyChange(name, oldValue, Float.valueOf(value));
}
/**
* Sets the value of the specified preference, overriding the value defined in the
* configuration files shipped with the application.
*/
public void setValue (String name, boolean value)
{
Boolean oldValue = null;
if (_prefs.get(name, null) != null || _props.getProperty(name) != null) {
oldValue = Boolean.valueOf(_prefs.getBoolean(name, super.getValue(name, false)));
}
_prefs.putBoolean(name, value);
_propsup.firePropertyChange(name, oldValue, Boolean.valueOf(value));
}
/**
* Sets the value of the specified preference, overriding the value defined in the
* configuration files shipped with the application.
*/
public void setValue (String name, String value)
{
String oldValue = getValue(name, (String)null);
_prefs.put(name, value);
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* Sets the value of the specified preference, overriding the value defined in the
* configuration files shipped with the application.
*/
public void setValue (String name, int[] value)
{
int[] oldValue = getValue(name, (int[])null);
_prefs.put(name, StringUtil.toString(value, "", ""));
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* Sets the value of the specified preference, overriding the value defined in the
* configuration files shipped with the application.
*/
public void setValue (String name, long[] value)
{
long[] oldValue = getValue(name, (long[])null);
_prefs.put(name, StringUtil.toString(value, "", ""));
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* Sets the value of the specified preference, overriding the value defined in the
* configuration files shipped with the application.
*/
public void setValue (String name, float[] value)
{
float[] oldValue = getValue(name, (float[])null);
_prefs.put(name, StringUtil.toString(value, "", ""));
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* Sets the value of the specified preference, overriding the value defined in the
* configuration files shipped with the application.
*/
public void setValue (String name, String[] value)
{
String[] oldValue = getValue(name, (String[])null);
_prefs.put(name, StringUtil.joinEscaped(value));
_propsup.firePropertyChange(name, oldValue, value);
}
/**
* Remove any set value for the specified preference.
*/
public void remove (String name)
{
// we treat the old value as a String, I hope that's ok!
String oldValue = getValue(name, (String) null);
_prefs.remove(name);
_propsup.firePropertyChange(name, oldValue, null);
}
/**
* Adds a listener that will be notified whenever any configuration properties are changed by a
* call to one of the <code>set</code> methods.
*/
public void addPropertyChangeListener (PropertyChangeListener listener)
{
_propsup.addPropertyChangeListener(listener);
}
/**
* Removes a property change listener previously added via a call to {@link
* #addPropertyChangeListener}.
*/
public void removePropertyChangeListener (PropertyChangeListener listener)
{
_propsup.removePropertyChangeListener(listener);
}
/**
* Adds a listener that will be notified whenever the specified configuration property is
* changed by a call to the appropriate <code>set</code> method.
*/
public void addPropertyChangeListener (String name, PropertyChangeListener listener)
{
_propsup.addPropertyChangeListener(name, listener);
}
/**
* Removes a property change listener previously added via a call to {@link
* #addPropertyChangeListener(String,PropertyChangeListener)}.
*/
public void removePropertyChangeListener (String name, PropertyChangeListener listener)
{
_propsup.removePropertyChangeListener(name, listener);
}
@Override // from Config
public int getValue (String name, int defval)
{
return _prefs.getInt(name, super.getValue(name, defval));
}
@Override // from Config
public long getValue (String name, long defval)
{
return _prefs.getLong(name, super.getValue(name, defval));
}
@Override // from Config
public float getValue (String name, float defval)
{
return _prefs.getFloat(name, super.getValue(name, defval));
}
@Override // from Config
public boolean getValue (String name, boolean defval)
{
return _prefs.getBoolean(name, super.getValue(name, defval));
}
@Override // from Config
public String getValue (String name, String defval)
{
return _prefs.get(name, super.getValue(name, defval));
}
@Override // from Config
protected void enumerateKeys (HashSet<String> keys)
{
super.enumerateKeys(keys);
try {
for (String key : _prefs.keys()) {
keys.add(key);
}
} catch (BackingStoreException bse) {
Log.warning("Unable to enumerate preferences keys [error=" + bse + "].");
}
}
/** This is used if we don't have security access to the preferences
* implementation that we'd like. */
protected static class NullPreferences extends AbstractPreferences
{
public NullPreferences () {
super(null, "");
}
protected void putSpi (String key, String value) {
}
protected String getSpi (String key) {
return null;
}
protected void removeSpi (String key) {
}
protected void removeNodeSpi () throws BackingStoreException {
}
protected String[] keysSpi () throws BackingStoreException {
return new String[0];
}
protected String[] childrenNamesSpi () throws BackingStoreException {
return new String[0];
}
protected AbstractPreferences childSpi (String name) {
return null;
}
protected void syncSpi () throws BackingStoreException {
}
protected void flushSpi () throws BackingStoreException {
}
}
/** Used to maintain configuration overrides. */
protected Preferences _prefs;
/** Used to support our property change mechanism. */
protected PropertyChangeSupport _propsup = new PropertyChangeSupport(this);
}
@@ -9,7 +9,7 @@ import java.util.Properties;
import junit.framework.Test;
import junit.framework.TestCase;
import com.samskivert.util.Config;
import com.samskivert.util.PrefsConfig;
import com.samskivert.util.StringUtil;
/**
@@ -24,7 +24,7 @@ public class ConfigTest extends TestCase
public void runTest ()
{
Config config = new Config("rsrc/util/test");
PrefsConfig config = new PrefsConfig("rsrc/util/test");
System.out.println("prop1: " + config.getValue("prop1", 1));
System.out.println("prop2: " + config.getValue("prop2", "two"));
@@ -51,8 +51,7 @@ public class ConfigTest extends TestCase
config.setValue("sub.sub3", "three");
Properties subprops = config.getSubProperties("sub");
System.out.println("Sub: " +
StringUtil.toString(subprops.propertyNames()));
System.out.println("Sub: " + StringUtil.toString(subprops.propertyNames()));
}
public static Test suite ()