openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From p..@apache.org
Subject svn commit: r417856 [16/22] - in /incubator/openjpa/trunk/openjpa-lib: java/ main/ main/java/ main/java/org/apache/openjpa/lib/ant/ main/java/org/apache/openjpa/lib/conf/ main/java/org/apache/openjpa/lib/jdbc/ main/java/org/apache/openjpa/lib/log/ main...
Date Wed, 28 Jun 2006 19:34:40 GMT
Modified: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/MultiClassLoader.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/MultiClassLoader.java?rev=417856&r1=415364&r2=417856&view=diff
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/MultiClassLoader.java (original)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/MultiClassLoader.java Wed Jun 28 12:34:33 2006
@@ -15,292 +15,280 @@
  */
 package org.apache.openjpa.lib.util;
 
-
 import java.io.*;
+
 import java.net.*;
+
 import java.util.*;
 
 
 /**
- *	<p>Class loader type that can be configured to delegate to multiple
- *	internal class loaders.</p>
+ *  <p>Class loader type that can be configured to delegate to multiple
+ *  internal class loaders.</p>
  *
- *	<p>The {@link #THREAD_LOADER} constant is a marker that will be replaced
- *	with the context loader of the current thread.</p>
+ *  <p>The {@link #THREAD_LOADER} constant is a marker that will be replaced
+ *  with the context loader of the current thread.</p>
  *
- *	@author		Abe White
+ *  @author Abe White
  */
-public class MultiClassLoader
-	extends ClassLoader
-{
-	/**
-	 *	Marker that will be replaced with the context loader of the current
-	 *	thread whenever it is discovered in the class loader list.
-	 */
-	public static final ClassLoader THREAD_LOADER = null;
-	
-	/**
-	 *	The standard system class loader.
-	 */
-	public static final ClassLoader SYSTEM_LOADER =
-		ClassLoader.getSystemClassLoader ();
-
-	private List _loaders = new ArrayList (5);
-
-
-	/**
-	 *	Constructor; initializes the loader with an empty list of delegates.
-	 */
-	public MultiClassLoader ()
-	{
-		super (null);
-	}
-
-
-	/**
-	 *	Construct with the class loaders of another multi loader.
-	 */
-	public MultiClassLoader (MultiClassLoader other)
-	{
-		super (null);
-		addClassLoaders (other);
-	}
-
-
-	/**
-	 *	Returns true if the list contains the given class loader or marker.
-	 */
-	public boolean containsClassLoader (ClassLoader loader)
-	{
-		return _loaders.contains (loader);
-	}
-
-
-	/**
-	 *	Return an array of all contained class loaders.
-	 */
-	public ClassLoader[] getClassLoaders ()
-	{
-		ClassLoader[] loaders = new ClassLoader[size ()];
-		ClassLoader loader;
-		Iterator itr = _loaders.iterator ();
-		for (int i = 0; i < loaders.length; i++)
-		{
-			loader = (ClassLoader) itr.next ();
-			if (loader == THREAD_LOADER)
-				loader = Thread.currentThread ().getContextClassLoader ();
-			loaders[i] = loader;
-		}
-		return loaders;
-	}
-
-
-	/**
-	 *	Return the class loader at the given index.
-	 */
-	public ClassLoader getClassLoader (int index)
-	{
-		ClassLoader loader = (ClassLoader) _loaders.get (index);
-		if (loader == THREAD_LOADER)
-			loader = Thread.currentThread ().getContextClassLoader ();
-		return loader;
-	}
-
-
-	/**
-	 *	Add the given class loader to the set of loaders that will be tried.
-	 *
-	 *	@return		true if the loader was added, false if already in the list
-	 */
-	public boolean addClassLoader (ClassLoader loader)
-	{
-		if (_loaders.contains (loader))
-			return false;
-		return _loaders.add (loader);
-	}
-
-
-	/**
-	 *	Add the given class loader at the specified index.
-	 *
-	 *	@return		true if the loader was added, false if already in the list
-	 */
-	public boolean addClassLoader (int index, ClassLoader loader)
-	{
-		if (_loaders.contains (loader))
-			return false;
-		_loaders.add (index, loader);
-		return true;
-	}
-
-
-	/**
-	 *	Set the class loaders of this loader to those of the given loader.
-	 */
-	public void setClassLoaders (MultiClassLoader multi)
-	{
-		clear ();
-		addClassLoaders (multi);
-	}
-
-
-	/**
-	 *	Adds all class loaders from the given multi loader starting at the
-	 *	given index.
-	 *
-	 *	@return 	true if any loaders were added, false if all already in list
-	 */
-	public boolean addClassLoaders (int index, MultiClassLoader multi)
-	{
-		if (multi == null)
-			return false;
-
-		// use iterator so that the thread loader is not resolved
-		boolean added = false;
-		for (Iterator itr = multi._loaders.iterator (); itr.hasNext ();)
-		{
-			if (addClassLoader (index, (ClassLoader) itr.next ()))
-			{
-				index++;
-				added = true;
-			}
-		}
-		return added;
-	}
-
-
-	/**
-	 *	Adds all the class loaders from the given multi loader.
-	 *
-	 *	@return 	true if any loaders were added, false if all already in list
-	 */
-	public boolean addClassLoaders (MultiClassLoader multi)
-	{
-		if (multi == null)
-			return false;
-
-		// use iterator so that the thread loader is not resolved
-		boolean added = false;
-		for (Iterator itr = multi._loaders.iterator (); itr.hasNext ();)
-			added = addClassLoader ((ClassLoader) itr.next ()) || added;	
-		return added;
-	}
-
-
-	/**
-	 *	Remove the given loader from the list.
-	 *
-	 *	@return		true if removed, false if not in list
-	 */
-	public boolean removeClassLoader (ClassLoader loader)
-	{
-		return _loaders.remove (loader);
-	}
-
-
-	/**
-	 *	Clear the list of class loaders.
-	 */
-	public void clear ()
-	{
-		_loaders.clear ();
-	}
-
-
-	/**
-	 *	Return the number of internal class loaders.
-	 */
-	public int size ()
-	{
-		return _loaders.size ();
-	}
-
-
-	/**
-	 *	Return true if there are no internal class laoders.
-	 */
-	public boolean isEmpty ()
-	{
-		return _loaders.isEmpty ();
-	}
-
-
-	protected Class findClass (String name)
-		throws ClassNotFoundException
-	{
-		ClassLoader loader;
-		for (Iterator itr = _loaders.iterator (); itr.hasNext ();)
-		{
-			loader = (ClassLoader) itr.next ();
-			if (loader == THREAD_LOADER)
-				loader = Thread.currentThread ().getContextClassLoader ();
-			try
-			{
-				return Class.forName (name, false, loader);
-			}
-			catch (Throwable t)
-			{
-			}	
-		}
-		throw new ClassNotFoundException (name);
-	} 
-
-	
-	protected URL findResource (String name)
-	{
-		ClassLoader loader;
-		URL rsrc;
-		for (Iterator itr = _loaders.iterator (); itr.hasNext ();)
-		{
-			loader = (ClassLoader) itr.next ();
-			if (loader == THREAD_LOADER)
-				loader = Thread.currentThread ().getContextClassLoader ();
-
-			rsrc = loader.getResource (name);
-			if (rsrc != null)
-				return rsrc;
-		}
-		return null;
-	}
-
-	
-	protected Enumeration findResources (String name)
-		throws IOException
-	{
-		ClassLoader loader;
-		Enumeration rsrcs;
-		Object rsrc;
-		Vector all = new Vector ();
-		for (Iterator itr = _loaders.iterator (); itr.hasNext ();)
-		{
-			loader = (ClassLoader) itr.next ();
-			if (loader == THREAD_LOADER)
-				loader = Thread.currentThread ().getContextClassLoader ();
-
-			rsrcs = loader.getResources (name);
-			while (rsrcs.hasMoreElements ())
-			{
-				rsrc = rsrcs.nextElement ();
-				if (!all.contains (rsrc))
-					all.addElement (rsrc);
-			}
-		}
-		return all.elements ();
-	}
-
-
-	public boolean equals (Object other)
-	{
-		if (other == this)
-			return true;
-		if (!(other instanceof MultiClassLoader))
-			return false;
-		return ((MultiClassLoader) other)._loaders.equals (_loaders);
-	}
-
-
-	public int hashCode ()
-	{
-		return _loaders.hashCode ();
-	}
+public class MultiClassLoader extends ClassLoader {
+    /**
+     *  Marker that will be replaced with the context loader of the current
+     *  thread whenever it is discovered in the class loader list.
+     */
+    public static final ClassLoader THREAD_LOADER = null;
+
+    /**
+     *  The standard system class loader.
+     */
+    public static final ClassLoader SYSTEM_LOADER = ClassLoader.getSystemClassLoader();
+    private List _loaders = new ArrayList(5);
+
+    /**
+     *  Constructor; initializes the loader with an empty list of delegates.
+     */
+    public MultiClassLoader() {
+        super(null);
+    }
+
+    /**
+     *  Construct with the class loaders of another multi loader.
+     */
+    public MultiClassLoader(MultiClassLoader other) {
+        super(null);
+        addClassLoaders(other);
+    }
+
+    /**
+     *  Returns true if the list contains the given class loader or marker.
+     */
+    public boolean containsClassLoader(ClassLoader loader) {
+        return _loaders.contains(loader);
+    }
+
+    /**
+     *  Return an array of all contained class loaders.
+     */
+    public ClassLoader[] getClassLoaders() {
+        ClassLoader[] loaders = new ClassLoader[size()];
+        ClassLoader loader;
+        Iterator itr = _loaders.iterator();
+
+        for (int i = 0; i < loaders.length; i++) {
+            loader = (ClassLoader) itr.next();
+
+            if (loader == THREAD_LOADER) {
+                loader = Thread.currentThread().getContextClassLoader();
+            }
+
+            loaders[i] = loader;
+        }
+
+        return loaders;
+    }
+
+    /**
+     *  Return the class loader at the given index.
+     */
+    public ClassLoader getClassLoader(int index) {
+        ClassLoader loader = (ClassLoader) _loaders.get(index);
+
+        if (loader == THREAD_LOADER) {
+            loader = Thread.currentThread().getContextClassLoader();
+        }
+
+        return loader;
+    }
+
+    /**
+     *  Add the given class loader to the set of loaders that will be tried.
+     *
+     *  @return true if the loader was added, false if already in the list
+     */
+    public boolean addClassLoader(ClassLoader loader) {
+        if (_loaders.contains(loader)) {
+            return false;
+        }
+
+        return _loaders.add(loader);
+    }
+
+    /**
+     *  Add the given class loader at the specified index.
+     *
+     *  @return true if the loader was added, false if already in the list
+     */
+    public boolean addClassLoader(int index, ClassLoader loader) {
+        if (_loaders.contains(loader)) {
+            return false;
+        }
+
+        _loaders.add(index, loader);
+
+        return true;
+    }
+
+    /**
+     *  Set the class loaders of this loader to those of the given loader.
+     */
+    public void setClassLoaders(MultiClassLoader multi) {
+        clear();
+        addClassLoaders(multi);
+    }
+
+    /**
+     *  Adds all class loaders from the given multi loader starting at the
+     *  given index.
+     *
+     *  @return true if any loaders were added, false if all already in list
+     */
+    public boolean addClassLoaders(int index, MultiClassLoader multi) {
+        if (multi == null) {
+            return false;
+        }
+
+        // use iterator so that the thread loader is not resolved
+        boolean added = false;
+
+        for (Iterator itr = multi._loaders.iterator(); itr.hasNext();) {
+            if (addClassLoader(index, (ClassLoader) itr.next())) {
+                index++;
+                added = true;
+            }
+        }
+
+        return added;
+    }
+
+    /**
+     *  Adds all the class loaders from the given multi loader.
+     *
+     *  @return true if any loaders were added, false if all already in list
+     */
+    public boolean addClassLoaders(MultiClassLoader multi) {
+        if (multi == null) {
+            return false;
+        }
+
+        // use iterator so that the thread loader is not resolved
+        boolean added = false;
+
+        for (Iterator itr = multi._loaders.iterator(); itr.hasNext();)
+            added = addClassLoader((ClassLoader) itr.next()) || added;
+
+        return added;
+    }
+
+    /**
+     *  Remove the given loader from the list.
+     *
+     *  @return true if removed, false if not in list
+     */
+    public boolean removeClassLoader(ClassLoader loader) {
+        return _loaders.remove(loader);
+    }
+
+    /**
+     *  Clear the list of class loaders.
+     */
+    public void clear() {
+        _loaders.clear();
+    }
+
+    /**
+     *  Return the number of internal class loaders.
+     */
+    public int size() {
+        return _loaders.size();
+    }
+
+    /**
+     *  Return true if there are no internal class laoders.
+     */
+    public boolean isEmpty() {
+        return _loaders.isEmpty();
+    }
+
+    protected Class findClass(String name) throws ClassNotFoundException {
+        ClassLoader loader;
+
+        for (Iterator itr = _loaders.iterator(); itr.hasNext();) {
+            loader = (ClassLoader) itr.next();
+
+            if (loader == THREAD_LOADER) {
+                loader = Thread.currentThread().getContextClassLoader();
+            }
+
+            try {
+                return Class.forName(name, false, loader);
+            } catch (Throwable t) {
+            }
+        }
+
+        throw new ClassNotFoundException(name);
+    }
+
+    protected URL findResource(String name) {
+        ClassLoader loader;
+        URL rsrc;
+
+        for (Iterator itr = _loaders.iterator(); itr.hasNext();) {
+            loader = (ClassLoader) itr.next();
+
+            if (loader == THREAD_LOADER) {
+                loader = Thread.currentThread().getContextClassLoader();
+            }
+
+            rsrc = loader.getResource(name);
+
+            if (rsrc != null) {
+                return rsrc;
+            }
+        }
+
+        return null;
+    }
+
+    protected Enumeration findResources(String name) throws IOException {
+        ClassLoader loader;
+        Enumeration rsrcs;
+        Object rsrc;
+        Vector all = new Vector();
+
+        for (Iterator itr = _loaders.iterator(); itr.hasNext();) {
+            loader = (ClassLoader) itr.next();
+
+            if (loader == THREAD_LOADER) {
+                loader = Thread.currentThread().getContextClassLoader();
+            }
+
+            rsrcs = loader.getResources(name);
+
+            while (rsrcs.hasMoreElements()) {
+                rsrc = rsrcs.nextElement();
+
+                if (!all.contains(rsrc)) {
+                    all.addElement(rsrc);
+                }
+            }
+        }
+
+        return all.elements();
+    }
+
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+
+        if (!(other instanceof MultiClassLoader)) {
+            return false;
+        }
+
+        return ((MultiClassLoader) other)._loaders.equals(_loaders);
+    }
+
+    public int hashCode() {
+        return _loaders.hashCode();
+    }
 }

Modified: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/Options.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/Options.java?rev=417856&r1=415364&r2=417856&view=diff
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/Options.java (original)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/Options.java Wed Jun 28 12:34:33 2006
@@ -15,677 +15,697 @@
  */
 package org.apache.openjpa.lib.util;
 
-
-import java.lang.reflect.*;
-import java.util.*;
-
 import org.apache.commons.collections.*;
 import org.apache.commons.lang.*;
+import org.apache.commons.lang.exception.*;
 
 import serp.util.*;
 
+import java.lang.reflect.*;
+
+import java.util.*;
+
 
 /**
- *	<p>A specialization of the {@link Properties} map type with the added
- *	abilities to read application options from the command line and to
- *	use bean patterns to set an object's properties via command-line the
- *	stored mappings.</p>
+ *  <p>A specialization of the {@link Properties} map type with the added
+ *  abilities to read application options from the command line and to
+ *  use bean patterns to set an object's properties via command-line the
+ *  stored mappings.</p>
  *
- *	<p>A typical use pattern for this class is to construct a new instance
- *	in the <code>main</code> method, then call {@link #setFromCmdLine} with the
- *	given args.  Next, an instanceof the class being invoked is created, and
- *	{@link #setInto} is called with that instance as a parameter.  With this
- *	pattern, the user can configure any bean properties of the class, or even
- *	properties of classes reachable from the class, through the command 
- *	line.</p>
+ *  <p>A typical use pattern for this class is to construct a new instance
+ *  in the <code>main</code> method, then call {@link #setFromCmdLine} with the
+ *  given args.  Next, an instanceof the class being invoked is created, and
+ *  {@link #setInto} is called with that instance as a parameter.  With this
+ *  pattern, the user can configure any bean properties of the class, or even
+ *  properties of classes reachable from the class, through the command
+ *  line.</p>
  *
- *	@author		Abe White
- *	@nojavadoc
- */
-public class Options
-	extends TypedProperties
-{
-	// maps primitive types to the appropriate wrapper class and default value
-	private static Object[][] _primWrappers = new Object[][] { 
-		{ boolean.class, Boolean.class, Boolean.FALSE },
-		{ byte.class, Byte.class, new Byte ((byte) 0) },
-		{ char.class, Character.class, new Character ((char) 0) },
-		{ double.class, Double.class, new Double (0D) },
-		{ float.class, Float.class, new Float (0F) },
-		{ int.class, Integer.class, new Integer (0) },
-		{ long.class, Long.class, new Long (0L) },
-		{ short.class, Short.class, new Short ((short) 0) },
-	};
-
-
-	/**
-	 *	Default constructor.
-	 */
-	public Options ()
-	{
-		super ();
-	}
-
-
-	/**
-	 *	Construct the options instance with the given set of defaults.
-	 *
-	 *	@see	Properties#Properties(Properties)
-	 */
-	public Options (Properties defaults)
-	{
-		super (defaults);
-	}
-
-
-	/**
-	 *	Parses the given argument list into flag/value pairs, which are stored
-	 *	as properties.  Flags that are present without values are given
-	 *	the value "true".  If any flag is found for which there is already
-	 *	a mapping present, the existing mapping will be overwritten.
-	 *	Flags should be of the form:<br />
-	 *	<code>java Foo -flag1 value1 -flag2 value2 ... arg1 arg2 ...</code>
-	 *
-	 *	@param	args	the command-line arguments
-	 *	@return			all arguments in the original array beyond the 
-	 *					flag/value pair list
- 	 *	@author			Patrick Linskey
-	 */
-	public String[] setFromCmdLine (String[] args)
-	{
-		if (args == null || args.length == 0)
-			return args;
-
-		String key = null;
-		String value = null;
-		List remainder = new LinkedList ();
-		for (int i = 0; i < args.length + 1; i++)
-		{
-			if (i == args.length || args[i].startsWith ("-"))
-			{
-				key = trimQuote (key);
-				if (key != null)
-				{
-					if (value != null && value.length () > 0)
-						setProperty (key, trimQuote (value));
-					else
-						setProperty (key, "true");
-				}
-
-				if (i == args.length)
-					break;
-				else
-				{
-					key = args[i].substring (1);
-					value = null;
-				}
-			}
-			else if (key != null)
-			{
-				setProperty (key, trimQuote (args[i]));
-				key = null;
-			}
-			else
-				remainder.add (args[i]);
-		}
-
-		return (String[]) remainder.toArray (new String[remainder.size ()]);
-	}
-
-
-	/**
-	 *	This method uses reflection to set all the properties in the given
-	 *	object that are named by the keys in this map. For a given key 'foo', 
-	 *	the algorithm will look for a 'setFoo' method in the given instance.  
-	 *	For a given key 'foo.bar', the algorithm will first look for a  
-	 *	'getFoo' method in the given instance, then will recurse on the return
-	 *	value of that method, now looking for the 'bar'	property.  This allows
-	 *	the setting of nested object properties.  If in the above example the 
-	 *	'getFoo' method is not present or returns null, the	algorithm will 
-	 *	look for a 'setFoo' method; if found it will constrct a new instance
-	 *	of the correct type, set it using the 'setFoo' method, then recurse on
-	 *	it as above.  Property names can be nested in this way to an arbitrary
-	 *	depth.  For setter methods that take multiple parameters, the value
-	 *	mapped to the key can use the ',' as an argument separator character.
-	 *	If not enough values are present for a given method after splitting 
-	 *	the string on ',', the remaining arguments will receive default 
-	 *	values.  All arguments are converted from string form to the
-	 *	correct type if possible (i.e. if the type is primitive,
-	 *	java.lang.Clas, or has a constructor that takes a single string
-	 *	argument).  Examples:
-	 *	<ul>	
-	 *	<li>Map Entry: <code>"age"-&gt;"12"</code><br />
-	 *		Resultant method call: <code>obj.setAge (12)</code></li>
-	 *	<li>Map Entry: <code>"range"-&gt;"1,20"</code><br />
-	 *		Resultant method call: <code>obj.setRange (1, 20)</code></li>
-	 *	<li>Map Entry: <code>"range"-&gt;"10"</code><br />
-	 *		Resultant method call: <code>obj.setRange (10, 10)</code></li>
-	 *	<li>Map Entry: <code>"brother.name"-&gt;"Bob"</code><br />
-	 *		Resultant method call: <code>obj.getBrother ().setName ("Bob")
-	 *		<code></li>
-	 *	</ul>
-	 *
-	 *	Any keys present in the map for which there is no
-	 *	corresponding property in the given object will be ignored,
-	 *	and will be returned in the {@link Map} returned by this
-	 *	method.
-	 *
-	 *	@return		a {@link Map} of key-value pairs in this object 
-	 *				for which no setters could be found.
-	 *	@throws		RuntimeException on parse error
-	 */
-	public Map setInto (Object obj)
-	{
-		// set all defaults that have no explicit value 
-		Map.Entry entry = null;
-		if (defaults != null)
-		{
-			for (Iterator itr = defaults.entrySet ().iterator(); itr.hasNext();)
-			{
-				entry = (Map.Entry) itr.next ();
-				if (!containsKey (entry.getKey ()))
-					setInto (obj, entry);
-			}
-		}
-
-		// set from main map
-		Map invalidEntries = null;
-		Map.Entry e;
-		for (Iterator itr = entrySet ().iterator (); itr.hasNext ();)
-		{
-			e = (Map.Entry) itr.next ();
-			if (!setInto (obj, e))
-			{
-				if (invalidEntries == null)
-					invalidEntries = new HashMap ();
-				invalidEntries.put (e.getKey (), e.getValue ());
-			}
-		}
-
-		return (invalidEntries == null) ? MapUtils.EMPTY_MAP : invalidEntries;
-	}
-
-
-	/**
-	 *	Sets the property named by the key of the given entry in the
-	 *	given object.
-	 *
-	 *	@return <code>true</code> if the set succeeded, or
-	 *			<code>false</code> if no method could be found for 
-	 *			this property.
-	 */
-	private boolean setInto (Object obj, Map.Entry entry)
-	{
-		if (entry.getKey () == null)
-			return false;
-
-		try
-		{
-			// look for matching parameter of object
-			Object[] match = new Object[] { obj, null };
-			if (!matchOptionToMember (entry.getKey ().toString (), match))
-				return false;
-
-			Class[] type = getType (match[1]);
-			Object[] values = new Object[type.length];
-			String[] strValues;
-			if (entry.getValue () == null)
-				strValues = new String[1];
-			else if (values.length == 1)
-				strValues = new String[] { entry.getValue ().toString () };
-			else
-				strValues = Strings.split (entry.getValue ().toString (), 
-					",", 0);
-
-			// convert the string values into parameter values, if not
-			// enough string values repeat last one for rest
-			for (int i = 0; i < strValues.length; i++)
-				values[i] = stringToObject (strValues[i].trim (), type[i]);
-			for (int i = strValues.length; i < values.length; i++)	
-				values[i] = getDefaultValue (type[i]);
-
-			// invoke the setter / set the field
-			invoke (match[0], match[1], values); 
-			return true;
-		}
-		catch (Throwable t)
-		{
-			throw new ParseException (obj + "." + entry.getKey () 
-				+ " = " + entry.getValue (), t);
-		}
-	} 
-
-
-	/**
-	 *	Removes leading and trailing single quotes from the given String, 
-	 *	if any.
- 	 */
-	private static String trimQuote (String val)
-	{
-		if (val != null && val.startsWith ("'") && val.endsWith ("'"))
-			return val.substring (1, val.length () - 1);
-		return val;
-	}
-
-
-	/**
-	 *	Finds all the options that can be set on the provided class. This does
-	 *	not look for path-traversal expressions.
-	 *
-	 *	@param	type	The class for which available options should be listed.
-	 *	@return			The available option names in <code>type</code>. The
-	 * 					names will have initial caps. They will be ordered
-	 * 					alphabetically.
-	 */
-	public static Collection findOptionsFor (Class type)
-	{
-		Collection names = new TreeSet ();
-		// look for a setter method matching the key
-		Method[] meths = type.getMethods ();
-		Class[] params;
-		for (int i = 0; i < meths.length; i++)
-		{
-			if (meths[i].getName ().startsWith ("set"))
-			{
-				params = meths[i].getParameterTypes ();
-				if (params.length == 0)
-					continue;
-				if (params[0].isArray ())
-					continue;
-
-				names.add (StringUtils.capitalize (
-					meths[i].getName ().substring (3)));
-			}
-		}
-
-		// check for public fields
-		Field[] fields = type.getFields ();
-		for (int i = 0; i < fields.length; i++)
-			names.add (StringUtils.capitalize (fields[i].getName ()));
-
-		return names;
-	}
-
-
-	/**
-	 *	Matches a key to an object/setter pair.  
-	 *
-	 *	@param	key		the key given at the command line; may be of the form
-	 *					'foo.bar' to signify the 'bar' property of the
-	 *					'foo' owned object
-	 *	@param	match	an array of length 2, where the first index is set
-	 *					to the object to retrieve the setter for
-	 *	@return			true if a match was made, false otherwise; additionally,
-	 *					the first index of the match array will be set to
-	 *					the matching object and the second index will be
-	 *					set to the setter method or public field for the 
-	 *					property named by the key
-	 */
-	private static boolean matchOptionToMember (String key, Object[] match)
-		throws Exception
-	{
-		if (key == null || key.length () == 0)
-			return false;
-		
-		// unfortunately we can't use bean properties for setters; any
-		// setter with more than 1 arg is ignored; calc setter and getter 
-		// name to look for
-		String[] find = Strings.split (key, ".", 2);
-		String base = StringUtils.capitalize (find[0]);
-		String set = "set" + base;
-		String get = "get" + base;
-
-		// look for a setter/getter matching the key; look for methods first
-		Class type = match[0].getClass ();
-		Method[] meths = type.getMethods ();
-		Method setMeth = null;
-		Method getMeth = null;
-		Class[] params;
-		for (int i = 0; i < meths.length; i++)
-		{
-			if (meths[i].getName ().equals (set))
-			{
-				params = meths[i].getParameterTypes ();
-				if (params.length == 0)
-					continue;
-				if (params[0].isArray ())
-					continue;
-
-				// use this method if we haven't found any other setter, if
-				// it has less parameters than any other setter, or if it uses
-				// string parameters
-				if (setMeth == null) 
-					setMeth = meths[i];
-				else if (params.length < setMeth.getParameterTypes ().length)
-					setMeth = meths[i];
-				else if (params.length == setMeth.getParameterTypes ().length
-					&& params[0] == String.class)
-					setMeth = meths[i];
-			}
-			else if (meths[i].getName ().equals (get))
-				getMeth = meths[i];
-		}
-
-		// if no methods found, check for public field
-		Member setter = setMeth;
-		Member getter = getMeth;
-		if (setter == null)
-		{
-			Field[] fields = type.getFields ();
-			String uncapBase = StringUtils.uncapitalize (find[0]);
-			for (int i = 0; i < fields.length; i++)
-			{
-				if (fields[i].getName ().equals (base) 
-					|| fields[i].getName ().equals (uncapBase))
-				{
-					setter = fields[i];
-					getter = fields[i];
-					break;
-				}
-			}
-		}
-
-		// if no way to access property, give up
-		if (setter == null && getter == null)
-			return false;
-
-		// recurse on inner object with remainder of key?
-		if (find.length > 1)
-		{
-			Object inner = null;
-			if (getter != null)
-				inner = invoke (match[0], getter, null);
-
-			// if no getter or current inner is null, try to create a new 
-			// inner instance and set it in object
-			if (inner == null && setter != null)
-			{
-				Class innerType = getType (setter)[0];
-				inner = innerType.newInstance ();
-				invoke (match[0], setter, new Object[] { inner });
-			}
-			match[0] = inner;
-			return matchOptionToMember (find[1], match);
-		}
-
-		// got match; find setter for property
-		match[1] = setter;
-		return match[1] != null;
-	}
-
-
-	/**
-	 *	Return the types of the parameters needed to set the given member.
-	 */
-	private static Class[] getType (Object member)
-	{
-		if (member instanceof Method)
-			return ((Method) member).getParameterTypes ();
-		return new Class[] { ((Field) member).getType () };
-	}
-
-
-	/**
-	 *	Set the given member to the given value(s).
-	 */
-	private static Object invoke (Object target, Object member, Object[] values)
-		throws Exception
-	{
-		if (member instanceof Method)
-			return ((Method) member).invoke (target, values);
-		if (values == null || values.length == 0)
-			return ((Field) member).get (target);
-		((Field) member).set (target, values[0]);
-		return null;
-	}
-
-
-	/**
-	 *	Converts the given string into an object of the given type, or its
-	 *	wrapper type if it is primitive.
-	 */
-	private Object stringToObject (String str, Class type)
-		throws Exception
-	{
-		// special case for null and for strings
-		if (str == null || type == String.class)
-			return str;
-
-		// special case for creating Class instances
-		if (type == Class.class)
-			return Class.forName (str, false, getClass ().getClassLoader ());
-
-		// special case for numeric types that end in .0; strip the decimal
-		// places because it can kill int, short, long parsing
-		if (type.isPrimitive () || Number.class.isAssignableFrom (type))
-			if (str.length () > 2 && str.endsWith (".0"))
-				str = str.substring (0, str.length () - 2);
-		
-		// for primitives, recurse on wrapper type
-		if (type.isPrimitive ())
-			for (int i = 0; i < _primWrappers.length; i++)
-				if (type == _primWrappers[i][0])
-					return stringToObject (str, (Class) _primWrappers[i][1]);	
-
-		// look for a string constructor
-		Exception err = null;
-		try
-		{
-			Constructor cons = type.getConstructor 
-				(new Class[] { String.class });
-			if (type == Boolean.class && "t".equalsIgnoreCase (str))
-				str = "true";
-			return cons.newInstance (new Object[] { str });	
-		}
-		catch (Exception e)
-		{
-			err = e;
-		}
-
-		// special case: the arg value is a subtype name and a new instance
-		// of that type should be set as the object
-		Class subType = null;
-		try
-		{
-			subType = Class.forName (str);
-		}
-		catch (Exception e)
-		{
-			throw err;
-		}
-		if (!type.isAssignableFrom (subType))
-			throw err;
-		return subType.newInstance ();
-	}
-
-
-	/**
-	 *	Returns the default value for the given parameter type.
-	 */
-	private Object getDefaultValue (Class type)
-	{
-		for (int i = 0; i < _primWrappers.length; i++)
-			if (_primWrappers[i][0] == type)
-				return _primWrappers[i][2];
-		
-		return null;
-	}
-
-
-	/**
-	 *	Specialization of {@link #getBooleanProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public boolean getBooleanProperty (String key, String key2, boolean def)
-	{
-		String val = getProperty (key);
-		if (val == null)
-			val = getProperty (key2);
-		if (val == null)
-			return def;
-		return "t".equalsIgnoreCase (val) || "true".equalsIgnoreCase (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link TypedProperties#getFloatProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public float getFloatProperty (String key, String key2, float def)
-	{
-		String val = getProperty (key);
-		if (val == null)
-			val = getProperty (key2);
-		return (val == null) ? def : Float.parseFloat (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link TypedProperties#getDoubleProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public double getDoubleProperty (String key, String key2, double def)
-	{
-		String val = getProperty (key);
-		if (val == null)
-			val = getProperty (key2);
-		return (val == null) ? def : Double.parseDouble (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link TypedProperties#getLongProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public long getLongProperty (String key, String key2, long def)
-	{
-		String val = getProperty (key);
-		if (val == null)
-			val = getProperty (key2);
-		return (val == null) ? def : Long.parseLong (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link TypedProperties#getIntProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public int getIntProperty (String key, String key2, int def)
-	{
-		String val = getProperty (key);
-		if (val == null)
-			val = getProperty (key2);
-		return (val == null) ? def : Integer.parseInt (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link Properties#getProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public String getProperty (String key, String key2, String def)
-	{
-		String val = getProperty (key);
-		return (val == null) ? getProperty (key2, def) : val;
-	}
-
-
-	/**
-	 *	Specialization of {@link TypedProperties#removeBooleanProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public boolean removeBooleanProperty (String key, String key2, boolean def)
-	{
-		String val = removeProperty (key);
-		if (val == null)
-			val = removeProperty (key2);
-		else
-			removeProperty (key2);
-		if (val == null)
-			return def;
-		return "t".equalsIgnoreCase (val) || "true".equalsIgnoreCase (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link TypedProperties#removeFloatProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public float removeFloatProperty (String key, String key2, float def)
-	{
-		String val = removeProperty (key);
-		if (val == null)
-			val = removeProperty (key2);
-		else
-			removeProperty (key2);
-		return (val == null) ? def : Float.parseFloat (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link TypedProperties#removeDoubleProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public double removeDoubleProperty (String key, String key2, double def)
-	{
-		String val = removeProperty (key);
-		if (val == null)
-			val = removeProperty (key2);
-		else
-			removeProperty (key2);
-		return (val == null) ? def : Double.parseDouble (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link TypedProperties#removeLongProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public long removeLongProperty (String key, String key2, long def)
-	{
-		String val = removeProperty (key);
-		if (val == null)
-			val = removeProperty (key2);
-		else
-			removeProperty (key2);
-		return (val == null) ? def : Long.parseLong (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link TypedProperties#removeIntProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public int removeIntProperty (String key, String key2, int def)
-	{
-		String val = removeProperty (key);
-		if (val == null)
-			val = removeProperty (key2);
-		else
-			removeProperty (key2);
-		return (val == null) ? def : Integer.parseInt (val);
-	}
-
-
-	/**
-	 *	Specialization of {@link Properties#removeProperty} to allow
-	 *	a value to appear under either of two keys; useful for short and
-	 *	long versions of command-line flags.
-	 */
-	public String removeProperty (String key, String key2, String def)
-	{
-		String val = removeProperty (key);
-		return (val == null) ? removeProperty (key2, def) : val;
-	}
+ *  @author Abe White
+ *  @nojavadoc */
+public class Options extends TypedProperties {
+    // maps primitive types to the appropriate wrapper class and default value
+    private static Object[][] _primWrappers = new Object[][] {
+            { boolean.class, Boolean.class, Boolean.FALSE },
+            { byte.class, Byte.class, new Byte((byte) 0) },
+            { char.class, Character.class, new Character((char) 0) },
+            { double.class, Double.class, new Double(0D) },
+            { float.class, Float.class, new Float(0F) },
+            { int.class, Integer.class, new Integer(0) },
+            { long.class, Long.class, new Long(0L) },
+            { short.class, Short.class, new Short((short) 0) },
+        };
+
+    /**
+     *  Default constructor.
+     */
+    public Options() {
+        super();
+    }
+
+    /**
+     *  Construct the options instance with the given set of defaults.
+     *
+     *  @see Properties#Properties(Properties)
+     */
+    public Options(Properties defaults) {
+        super(defaults);
+    }
+
+    /**
+     *  Parses the given argument list into flag/value pairs, which are stored
+     *  as properties.  Flags that are present without values are given
+     *  the value "true".  If any flag is found for which there is already
+     *  a mapping present, the existing mapping will be overwritten.
+     *  Flags should be of the form:<br />
+     *  <code>java Foo -flag1 value1 -flag2 value2 ... arg1 arg2 ...</code>
+     *
+     *  @param args        the command-line arguments
+     *  @return all arguments in the original array beyond the
+     *                                  flag/value pair list
+      *  @author Patrick Linskey
+     */
+    public String[] setFromCmdLine(String[] args) {
+        if ((args == null) || (args.length == 0)) {
+            return args;
+        }
+
+        String key = null;
+        String value = null;
+        List remainder = new LinkedList();
+
+        for (int i = 0; i < (args.length + 1); i++) {
+            if ((i == args.length) || args[i].startsWith("-")) {
+                key = trimQuote(key);
+
+                if (key != null) {
+                    if ((value != null) && (value.length() > 0)) {
+                        setProperty(key, trimQuote(value));
+                    } else {
+                        setProperty(key, "true");
+                    }
+                }
+
+                if (i == args.length) {
+                    break;
+                } else {
+                    key = args[i].substring(1);
+                    value = null;
+                }
+            } else if (key != null) {
+                setProperty(key, trimQuote(args[i]));
+                key = null;
+            } else {
+                remainder.add(args[i]);
+            }
+        }
+
+        return (String[]) remainder.toArray(new String[remainder.size()]);
+    }
+
+    /**
+     *  This method uses reflection to set all the properties in the given
+     *  object that are named by the keys in this map. For a given key 'foo',
+     *  the algorithm will look for a 'setFoo' method in the given instance.
+     *  For a given key 'foo.bar', the algorithm will first look for a
+     *  'getFoo' method in the given instance, then will recurse on the return
+     *  value of that method, now looking for the 'bar'        property.  This allows
+     *  the setting of nested object properties.  If in the above example the
+     *  'getFoo' method is not present or returns null, the        algorithm will
+     *  look for a 'setFoo' method; if found it will constrct a new instance
+     *  of the correct type, set it using the 'setFoo' method, then recurse on
+     *  it as above.  Property names can be nested in this way to an arbitrary
+     *  depth.  For setter methods that take multiple parameters, the value
+     *  mapped to the key can use the ',' as an argument separator character.
+     *  If not enough values are present for a given method after splitting
+     *  the string on ',', the remaining arguments will receive default
+     *  values.  All arguments are converted from string form to the
+     *  correct type if possible (i.e. if the type is primitive,
+     *  java.lang.Clas, or has a constructor that takes a single string
+     *  argument).  Examples:
+     *  <ul>
+     *  <li>Map Entry: <code>"age"-&gt;"12"</code><br />
+     *          Resultant method call: <code>obj.setAge (12)</code></li>
+     *  <li>Map Entry: <code>"range"-&gt;"1,20"</code><br />
+     *          Resultant method call: <code>obj.setRange (1, 20)</code></li>
+     *  <li>Map Entry: <code>"range"-&gt;"10"</code><br />
+     *          Resultant method call: <code>obj.setRange (10, 10)</code></li>
+     *  <li>Map Entry: <code>"brother.name"-&gt;"Bob"</code><br />
+     *          Resultant method call: <code>obj.getBrother ().setName ("Bob")
+     *          <code></li>
+     *  </ul>
+     *
+     *  Any keys present in the map for which there is no
+     *  corresponding property in the given object will be ignored,
+     *  and will be returned in the {@link Map} returned by this
+     *  method.
+     *
+     *  @return a {@link Map} of key-value pairs in this object
+     *                          for which no setters could be found.
+     *  @throws RuntimeException on parse error
+     */
+    public Map setInto(Object obj) {
+        // set all defaults that have no explicit value 
+        Map.Entry entry = null;
+
+        if (defaults != null) {
+            for (Iterator itr = defaults.entrySet().iterator(); itr.hasNext();) {
+                entry = (Map.Entry) itr.next();
+
+                if (!containsKey(entry.getKey())) {
+                    setInto(obj, entry);
+                }
+            }
+        }
+
+        // set from main map
+        Map invalidEntries = null;
+        Map.Entry e;
+
+        for (Iterator itr = entrySet().iterator(); itr.hasNext();) {
+            e = (Map.Entry) itr.next();
+
+            if (!setInto(obj, e)) {
+                if (invalidEntries == null) {
+                    invalidEntries = new HashMap();
+                }
+
+                invalidEntries.put(e.getKey(), e.getValue());
+            }
+        }
+
+        return (invalidEntries == null) ? Collections.EMPTY_MAP : invalidEntries;
+    }
+
+    /**
+     *  Sets the property named by the key of the given entry in the
+     *  given object.
+     *
+     *  @return <code>true</code> if the set succeeded, or
+     *                  <code>false</code> if no method could be found for
+     *                  this property.
+     */
+    private boolean setInto(Object obj, Map.Entry entry) {
+        if (entry.getKey() == null) {
+            return false;
+        }
+
+        try {
+            // look for matching parameter of object
+            Object[] match = new Object[] { obj, null };
+
+            if (!matchOptionToMember(entry.getKey().toString(), match)) {
+                return false;
+            }
+
+            Class[] type = getType(match[1]);
+            Object[] values = new Object[type.length];
+            String[] strValues;
+
+            if (entry.getValue() == null) {
+                strValues = new String[1];
+            } else if (values.length == 1) {
+                strValues = new String[] { entry.getValue().toString() };
+            } else {
+                strValues = Strings.split(entry.getValue().toString(), ",", 0);
+            }
+
+            // convert the string values into parameter values, if not
+            // enough string values repeat last one for rest
+            for (int i = 0; i < strValues.length; i++)
+                values[i] = stringToObject(strValues[i].trim(), type[i]);
+
+            for (int i = strValues.length; i < values.length; i++)
+                values[i] = getDefaultValue(type[i]);
+
+            // invoke the setter / set the field
+            invoke(match[0], match[1], values);
+
+            return true;
+        } catch (Throwable t) {
+            throw new ParseException(obj + "." + entry.getKey() + " = " +
+                entry.getValue(), t);
+        }
+    }
+
+    /**
+     *  Removes leading and trailing single quotes from the given String,
+     *  if any.
+      */
+    private static String trimQuote(String val) {
+        if ((val != null) && val.startsWith("'") && val.endsWith("'")) {
+            return val.substring(1, val.length() - 1);
+        }
+
+        return val;
+    }
+
+    /**
+     *  Finds all the options that can be set on the provided class. This does
+     *  not look for path-traversal expressions.
+     *
+     *  @param type        The class for which available options should be listed.
+     *  @return The available option names in <code>type</code>. The
+     *                                  names will have initial caps. They will be ordered
+     *                                  alphabetically.
+     */
+    public static Collection findOptionsFor(Class type) {
+        Collection names = new TreeSet();
+
+        // look for a setter method matching the key
+        Method[] meths = type.getMethods();
+        Class[] params;
+
+        for (int i = 0; i < meths.length; i++) {
+            if (meths[i].getName().startsWith("set")) {
+                params = meths[i].getParameterTypes();
+
+                if (params.length == 0) {
+                    continue;
+                }
+
+                if (params[0].isArray()) {
+                    continue;
+                }
+
+                names.add(StringUtils.capitalize(meths[i].getName().substring(3)));
+            }
+        }
+
+        // check for public fields
+        Field[] fields = type.getFields();
+
+        for (int i = 0; i < fields.length; i++)
+            names.add(StringUtils.capitalize(fields[i].getName()));
+
+        return names;
+    }
+
+    /**
+     *  Matches a key to an object/setter pair.
+     *
+     *  @param key                the key given at the command line; may be of the form
+     *                                  'foo.bar' to signify the 'bar' property of the
+     *                                  'foo' owned object
+     *  @param match        an array of length 2, where the first index is set
+     *                                  to the object to retrieve the setter for
+     *  @return true if a match was made, false otherwise; additionally,
+     *                                  the first index of the match array will be set to
+     *                                  the matching object and the second index will be
+     *                                  set to the setter method or public field for the
+     *                                  property named by the key
+     */
+    private static boolean matchOptionToMember(String key, Object[] match)
+        throws Exception {
+        if ((key == null) || (key.length() == 0)) {
+            return false;
+        }
+
+        // unfortunately we can't use bean properties for setters; any
+        // setter with more than 1 arg is ignored; calc setter and getter 
+        // name to look for
+        String[] find = Strings.split(key, ".", 2);
+        String base = StringUtils.capitalise(find[0]);
+        String set = "set" + base;
+        String get = "get" + base;
+
+        // look for a setter/getter matching the key; look for methods first
+        Class type = match[0].getClass();
+        Method[] meths = type.getMethods();
+        Method setMeth = null;
+        Method getMeth = null;
+        Class[] params;
+
+        for (int i = 0; i < meths.length; i++) {
+            if (meths[i].getName().equals(set)) {
+                params = meths[i].getParameterTypes();
+
+                if (params.length == 0) {
+                    continue;
+                }
+
+                if (params[0].isArray()) {
+                    continue;
+                }
+
+                // use this method if we haven't found any other setter, if
+                // it has less parameters than any other setter, or if it uses
+                // string parameters
+                if (setMeth == null) {
+                    setMeth = meths[i];
+                } else if (params.length < setMeth.getParameterTypes().length) {
+                    setMeth = meths[i];
+                } else if ((params.length == setMeth.getParameterTypes().length) &&
+                        (params[0] == String.class)) {
+                    setMeth = meths[i];
+                }
+            } else if (meths[i].getName().equals(get)) {
+                getMeth = meths[i];
+            }
+        }
+
+        // if no methods found, check for public field
+        Member setter = setMeth;
+        Member getter = getMeth;
+
+        if (setter == null) {
+            Field[] fields = type.getFields();
+            String uncapBase = StringUtils.uncapitalise(find[0]);
+
+            for (int i = 0; i < fields.length; i++) {
+                if (fields[i].getName().equals(base) ||
+                        fields[i].getName().equals(uncapBase)) {
+                    setter = fields[i];
+                    getter = fields[i];
+
+                    break;
+                }
+            }
+        }
+
+        // if no way to access property, give up
+        if ((setter == null) && (getter == null)) {
+            return false;
+        }
+
+        // recurse on inner object with remainder of key?
+        if (find.length > 1) {
+            Object inner = null;
+
+            if (getter != null) {
+                inner = invoke(match[0], getter, null);
+            }
+
+            // if no getter or current inner is null, try to create a new 
+            // inner instance and set it in object
+            if ((inner == null) && (setter != null)) {
+                Class innerType = getType(setter)[0];
+                inner = innerType.newInstance();
+                invoke(match[0], setter, new Object[] { inner });
+            }
+
+            match[0] = inner;
+
+            return matchOptionToMember(find[1], match);
+        }
+
+        // got match; find setter for property
+        match[1] = setter;
+
+        return match[1] != null;
+    }
+
+    /**
+     *  Return the types of the parameters needed to set the given member.
+     */
+    private static Class[] getType(Object member) {
+        if (member instanceof Method) {
+            return ((Method) member).getParameterTypes();
+        }
+
+        return new Class[] { ((Field) member).getType() };
+    }
+
+    /**
+     *  Set the given member to the given value(s).
+     */
+    private static Object invoke(Object target, Object member, Object[] values)
+        throws Exception {
+        if (member instanceof Method) {
+            return ((Method) member).invoke(target, values);
+        }
+
+        if ((values == null) || (values.length == 0)) {
+            return ((Field) member).get(target);
+        }
+
+        ((Field) member).set(target, values[0]);
+
+        return null;
+    }
+
+    /**
+     *  Converts the given string into an object of the given type, or its
+     *  wrapper type if it is primitive.
+     */
+    private Object stringToObject(String str, Class type)
+        throws Exception {
+        // special case for null and for strings
+        if ((str == null) || (type == String.class)) {
+            return str;
+        }
+
+        // special case for creating Class instances
+        if (type == Class.class) {
+            return Class.forName(str, false, getClass().getClassLoader());
+        }
+
+        // special case for numeric types that end in .0; strip the decimal
+        // places because it can kill int, short, long parsing
+        if (type.isPrimitive() || Number.class.isAssignableFrom(type)) {
+            if ((str.length() > 2) && str.endsWith(".0")) {
+                str = str.substring(0, str.length() - 2);
+            }
+        }
+
+        // for primitives, recurse on wrapper type
+        if (type.isPrimitive()) {
+            for (int i = 0; i < _primWrappers.length; i++)
+                if (type == _primWrappers[i][0]) {
+                    return stringToObject(str, (Class) _primWrappers[i][1]);
+                }
+        }
+
+        // look for a string constructor
+        Exception err = null;
+
+        try {
+            Constructor cons = type.getConstructor(new Class[] { String.class });
+
+            if ((type == Boolean.class) && "t".equalsIgnoreCase(str)) {
+                str = "true";
+            }
+
+            return cons.newInstance(new Object[] { str });
+        } catch (Exception e) {
+            err = e;
+        }
+
+        // special case: the arg value is a subtype name and a new instance
+        // of that type should be set as the object
+        Class subType = null;
+
+        try {
+            subType = Class.forName(str);
+        } catch (Exception e) {
+            throw err;
+        }
+
+        if (!type.isAssignableFrom(subType)) {
+            throw err;
+        }
+
+        return subType.newInstance();
+    }
+
+    /**
+     *  Returns the default value for the given parameter type.
+     */
+    private Object getDefaultValue(Class type) {
+        for (int i = 0; i < _primWrappers.length; i++)
+            if (_primWrappers[i][0] == type) {
+                return _primWrappers[i][2];
+            }
+
+        return null;
+    }
+
+    /**
+     *  Specialization of {@link #getBooleanProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public boolean getBooleanProperty(String key, String key2, boolean def) {
+        String val = getProperty(key);
+
+        if (val == null) {
+            val = getProperty(key2);
+        }
+
+        if (val == null) {
+            return def;
+        }
+
+        return "t".equalsIgnoreCase(val) || "true".equalsIgnoreCase(val);
+    }
+
+    /**
+     *  Specialization of {@link TypedProperties#getFloatProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public float getFloatProperty(String key, String key2, float def) {
+        String val = getProperty(key);
+
+        if (val == null) {
+            val = getProperty(key2);
+        }
+
+        return (val == null) ? def : Float.parseFloat(val);
+    }
+
+    /**
+     *  Specialization of {@link TypedProperties#getDoubleProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public double getDoubleProperty(String key, String key2, double def) {
+        String val = getProperty(key);
+
+        if (val == null) {
+            val = getProperty(key2);
+        }
+
+        return (val == null) ? def : Double.parseDouble(val);
+    }
+
+    /**
+     *  Specialization of {@link TypedProperties#getLongProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public long getLongProperty(String key, String key2, long def) {
+        String val = getProperty(key);
+
+        if (val == null) {
+            val = getProperty(key2);
+        }
+
+        return (val == null) ? def : Long.parseLong(val);
+    }
+
+    /**
+     *  Specialization of {@link TypedProperties#getIntProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public int getIntProperty(String key, String key2, int def) {
+        String val = getProperty(key);
+
+        if (val == null) {
+            val = getProperty(key2);
+        }
+
+        return (val == null) ? def : Integer.parseInt(val);
+    }
+
+    /**
+     *  Specialization of {@link Properties#getProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public String getProperty(String key, String key2, String def) {
+        String val = getProperty(key);
+
+        return (val == null) ? getProperty(key2, def) : val;
+    }
+
+    /**
+     *  Specialization of {@link TypedProperties#removeBooleanProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public boolean removeBooleanProperty(String key, String key2, boolean def) {
+        String val = removeProperty(key);
+
+        if (val == null) {
+            val = removeProperty(key2);
+        } else {
+            removeProperty(key2);
+        }
+
+        if (val == null) {
+            return def;
+        }
+
+        return "t".equalsIgnoreCase(val) || "true".equalsIgnoreCase(val);
+    }
+
+    /**
+     *  Specialization of {@link TypedProperties#removeFloatProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public float removeFloatProperty(String key, String key2, float def) {
+        String val = removeProperty(key);
+
+        if (val == null) {
+            val = removeProperty(key2);
+        } else {
+            removeProperty(key2);
+        }
+
+        return (val == null) ? def : Float.parseFloat(val);
+    }
+
+    /**
+     *  Specialization of {@link TypedProperties#removeDoubleProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public double removeDoubleProperty(String key, String key2, double def) {
+        String val = removeProperty(key);
+
+        if (val == null) {
+            val = removeProperty(key2);
+        } else {
+            removeProperty(key2);
+        }
+
+        return (val == null) ? def : Double.parseDouble(val);
+    }
+
+    /**
+     *  Specialization of {@link TypedProperties#removeLongProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public long removeLongProperty(String key, String key2, long def) {
+        String val = removeProperty(key);
+
+        if (val == null) {
+            val = removeProperty(key2);
+        } else {
+            removeProperty(key2);
+        }
+
+        return (val == null) ? def : Long.parseLong(val);
+    }
+
+    /**
+     *  Specialization of {@link TypedProperties#removeIntProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public int removeIntProperty(String key, String key2, int def) {
+        String val = removeProperty(key);
+
+        if (val == null) {
+            val = removeProperty(key2);
+        } else {
+            removeProperty(key2);
+        }
+
+        return (val == null) ? def : Integer.parseInt(val);
+    }
+
+    /**
+     *  Specialization of {@link Properties#removeProperty} to allow
+     *  a value to appear under either of two keys; useful for short and
+     *  long versions of command-line flags.
+     */
+    public String removeProperty(String key, String key2, String def) {
+        String val = removeProperty(key);
+
+        return (val == null) ? removeProperty(key2, def) : val;
+    }
 }

Modified: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ParameterTemplate.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ParameterTemplate.java?rev=417856&r1=415364&r2=417856&view=diff
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ParameterTemplate.java (original)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ParameterTemplate.java Wed Jun 28 12:34:33 2006
@@ -15,284 +15,249 @@
  */
 package org.apache.openjpa.lib.util;
 
-
 import java.io.*;
+
 import java.util.*;
 
 
 /**
- *	<p>A template that allows parameter substitutions.  Parameters should be
- *	placed in the template in the form ${param-name}.  Use the 
- *	{@link #setParameter} method to set the parameter values, which will be
- *	substituted into the template on calls to {@link #write} and
- *	{@link #toString}.  If a parameter is encountered that hasn't been set, then
- *	the parameter key is used to lookup the corresponding System property.</p>
+ *  <p>A template that allows parameter substitutions.  Parameters should be
+ *  placed in the template in the form ${param-name}.  Use the
+ *  {@link #setParameter} method to set the parameter values, which will be
+ *  substituted into the template on calls to {@link #write} and
+ *  {@link #toString}.  If a parameter is encountered that hasn't been set, then
+ *  the parameter key is used to lookup the corresponding System property.</p>
  *
- *	@author		Abe White
- *	@nojavadoc
- */
-public class ParameterTemplate
-{
-	private static final String SEP = System.getProperty ("line.separator");
-
-	private final StringBuffer	_buf 	= new StringBuffer ();
-	private final Map			_params	= new HashMap ();
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (String value)
-	{
-		_buf.append (value);
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (boolean value)
-	{
-		_buf.append (value);
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (char value)
-	{
-		_buf.append (value);
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (double value)
-	{
-		_buf.append (value);
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (float value)
-	{
-		_buf.append (value);
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (int value)
-	{
-		_buf.append (value);
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (long value)
-	{
-		_buf.append (value);
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (short value)
-	{
-		_buf.append (value);
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (Object value)
-	{
-		_buf.append (value);
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (InputStream in)
-		throws IOException
-	{
-		return append (new InputStreamReader (in));	
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (Reader reader)
-		throws IOException
-	{
-		BufferedReader buf = new BufferedReader (reader);
-		String line;
-		while ((line = buf.readLine ()) != null)
-			_buf.append (line).append (SEP);		
-		return this;
-	}
-
-
-	/**
-	 *	Add the given value to the internal template.
-	 */
-	public ParameterTemplate append (File file)
-		throws IOException
-	{
-		FileReader reader = new FileReader (file);
-		try 
-		{ 
-			return append (reader); 
-		} 
-		finally 
-		{ 
-			try { reader.close (); } catch (IOException ioe) {}
-		}
-	}
-
-
-	/**
-	 *	Return true if the given parameter has been given a value.
-	 */
-	public boolean hasParameter (String name)
-	{
-		return _params.containsKey (name);
-	}
-
-
-	/**
-	 *	Return the value set for the given parameter.
-	 */
-	public Object getParameter (String name)
-	{
-		return _params.get (name);
-	}
-
-
-	/**
-	 *	Set the value for the given parameter.
-	 */
-	public Object setParameter (String name, Object val)
-	{
-		return _params.put (name, val);
-	}
-
-
-	/**
-	 *	Set the values for all the parameters in the given map.
-	 */
-	public void setParameters (Map params)
-	{
-		_params.putAll (params);
-	}
-
-
-	/**
-	 *	Clear the recorded parameter values.
-	 */
-	public void clearParameters ()
-	{
-		_params.clear ();
-	}
-
-
-	/**
-	 *	Return a copy of the internal value template with all parameters
-	 *	substituted with their current values.
-	 */
-	public String toString ()
-	{
-		if (_buf.length () == 0 || _params.isEmpty ())
-			return _buf.toString ();
-
-		StringBuffer copy = new StringBuffer ();
-		StringBuffer param = null;
-		char ch, last = 0;
-		for (int i = 0; i < _buf.length (); i++)
-		{
-			ch = _buf.charAt (i);
-			if (last == '$' && ch == '{')
-			{
-				copy.deleteCharAt (copy.length () - 1);
-				param = new StringBuffer ();
-			}
-			else if (ch == '}' && param != null)
-			{
-				if (_params.containsKey (param.toString ()))
-					copy.append (_params.get (param.toString ()));
-				else
-					copy.append (System.getProperty (param.toString ()));
-				param = null;			
-			}
-			else if (param != null)
-				param.append (ch);
-			else
-				copy.append (ch);
-
-			last = ch;
-		}
-		return copy.toString ();
-	}
-
-
-	/**
-	 *	Write the internal value template with all parameters
-	 *	substituted with their current values.
-	 */
-	public void write (OutputStream out)
-		throws IOException
-	{
-		write (new OutputStreamWriter (out));
-	}
-
-
-	/**
-	 *	Write the internal value template with all parameters
-	 *	substituted with their current values.
-	 */
-	public void write (Writer writer)
-		throws IOException
-	{
-		writer.write (toString ());
-		writer.flush ();
-	}
-
-
-	/**
-	 *	Write the internal value template with all parameters
-	 *	substituted with their current values.
-	 */
-	public void write (File file)
-		throws IOException
-	{
-		FileWriter writer = new FileWriter (file);
-		try 
-		{ 
-			write (writer); 
-		} 
-		finally 
-		{ 
-			try { writer.close (); } catch (IOException ioe) {}
-		}
-	}
+ *  @author Abe White
+ *  @nojavadoc */
+public class ParameterTemplate {
+    private static final String SEP = System.getProperty("line.separator");
+    private final StringBuffer _buf = new StringBuffer();
+    private final Map _params = new HashMap();
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(String value) {
+        _buf.append(value);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(boolean value) {
+        _buf.append(value);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(char value) {
+        _buf.append(value);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(double value) {
+        _buf.append(value);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(float value) {
+        _buf.append(value);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(int value) {
+        _buf.append(value);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(long value) {
+        _buf.append(value);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(short value) {
+        _buf.append(value);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(Object value) {
+        _buf.append(value);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(InputStream in) throws IOException {
+        return append(new InputStreamReader(in));
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(Reader reader) throws IOException {
+        BufferedReader buf = new BufferedReader(reader);
+        String line;
+
+        while ((line = buf.readLine()) != null)
+            _buf.append(line).append(SEP);
+
+        return this;
+    }
+
+    /**
+     *  Add the given value to the internal template.
+     */
+    public ParameterTemplate append(File file) throws IOException {
+        FileReader reader = new FileReader(file);
+
+        try {
+            return append(reader);
+        } finally {
+            try {
+                reader.close();
+            } catch (IOException ioe) {
+            }
+        }
+    }
+
+    /**
+     *  Return true if the given parameter has been given a value.
+     */
+    public boolean hasParameter(String name) {
+        return _params.containsKey(name);
+    }
+
+    /**
+     *  Return the value set for the given parameter.
+     */
+    public Object getParameter(String name) {
+        return _params.get(name);
+    }
+
+    /**
+     *  Set the value for the given parameter.
+     */
+    public Object setParameter(String name, Object val) {
+        return _params.put(name, val);
+    }
+
+    /**
+     *  Set the values for all the parameters in the given map.
+     */
+    public void setParameters(Map params) {
+        _params.putAll(params);
+    }
+
+    /**
+     *  Clear the recorded parameter values.
+     */
+    public void clearParameters() {
+        _params.clear();
+    }
+
+    /**
+     *  Return a copy of the internal value template with all parameters
+     *  substituted with their current values.
+     */
+    public String toString() {
+        if ((_buf.length() == 0) || _params.isEmpty()) {
+            return _buf.toString();
+        }
+
+        StringBuffer copy = new StringBuffer();
+        StringBuffer param = null;
+        char ch;
+        char last = 0;
+
+        for (int i = 0; i < _buf.length(); i++) {
+            ch = _buf.charAt(i);
+
+            if ((last == '$') && (ch == '{')) {
+                copy.deleteCharAt(copy.length() - 1);
+                param = new StringBuffer();
+            } else if ((ch == '}') && (param != null)) {
+                if (_params.containsKey(param.toString())) {
+                    copy.append(_params.get(param.toString()));
+                } else {
+                    copy.append(System.getProperty(param.toString()));
+                }
+
+                param = null;
+            } else if (param != null) {
+                param.append(ch);
+            } else {
+                copy.append(ch);
+            }
+
+            last = ch;
+        }
+
+        return copy.toString();
+    }
+
+    /**
+     *  Write the internal value template with all parameters
+     *  substituted with their current values.
+     */
+    public void write(OutputStream out) throws IOException {
+        write(new OutputStreamWriter(out));
+    }
+
+    /**
+     *  Write the internal value template with all parameters
+     *  substituted with their current values.
+     */
+    public void write(Writer writer) throws IOException {
+        writer.write(toString());
+        writer.flush();
+    }
+
+    /**
+     *  Write the internal value template with all parameters
+     *  substituted with their current values.
+     */
+    public void write(File file) throws IOException {
+        FileWriter writer = new FileWriter(file);
+
+        try {
+            write(writer);
+        } finally {
+            try {
+                writer.close();
+            } catch (IOException ioe) {
+            }
+        }
+    }
 }

Modified: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ParseException.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ParseException.java?rev=417856&r1=415364&r2=417856&view=diff
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ParseException.java (original)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ParseException.java Wed Jun 28 12:34:33 2006
@@ -15,39 +15,28 @@
  */
 package org.apache.openjpa.lib.util;
 
-
 import org.apache.commons.lang.exception.*;
 
 
 /**
- *	<p>Exception type for parse errors.</p>
+ *  <p>Exception type for parse errors.</p>
  *
- *	@author		Abe White
- *	@since		4.0
- *	@nojavadoc
- */
-public class ParseException
-	extends NestableRuntimeException
-{
-	public ParseException ()
-	{
-	}
-
-
-	public ParseException (String msg)
-	{
-		super (msg);
-	}
-
-
-	public ParseException (Throwable cause)
-	{
-		super (cause);
-	}
-
-
-	public ParseException (String msg, Throwable cause)
-	{
-		super (msg, cause);
-	}
+ *  @author Abe White
+ *  @since 4.0
+ *  @nojavadoc */
+public class ParseException extends NestableRuntimeException {
+    public ParseException() {
+    }
+
+    public ParseException(String msg) {
+        super(msg);
+    }
+
+    public ParseException(Throwable cause) {
+        super(cause);
+    }
+
+    public ParseException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
 }

Added: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashMap.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashMap.java?rev=417856&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashMap.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashMap.java Wed Jun 28 12:34:33 2006
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.util;
+
+import java.io.*;
+
+import java.lang.ref.*;
+
+import java.util.*;
+
+
+/**
+ *  <p>Map in which the key, value, or both may be weak/soft references.</p>
+ *
+ *  @author Abe White
+ *  @since 4.0
+ *  @nojavadoc */
+public class ReferenceHashMap extends org.apache.commons.collections.map.ReferenceMap
+    implements ReferenceMap, SizedMap {
+    private int _maxSize = Integer.MAX_VALUE;
+
+    public ReferenceHashMap(int keyType, int valueType) {
+        super(toReferenceConstant(keyType), toReferenceConstant(valueType));
+    }
+
+    public ReferenceHashMap(int keyType, int valueType, int capacity,
+        float loadFactor) {
+        super(toReferenceConstant(keyType), toReferenceConstant(valueType),
+            capacity, loadFactor);
+    }
+
+    /**
+     *  Concver our reference constants to Apache's.
+     */
+    private static int toReferenceConstant(int type) {
+        switch (type) {
+        case ReferenceMap.HARD:
+            return org.apache.commons.collections.map.ReferenceMap.HARD;
+
+        case ReferenceMap.SOFT:
+            return org.apache.commons.collections.map.ReferenceMap.SOFT;
+
+        default:
+            return org.apache.commons.collections.map.ReferenceMap.WEAK;
+        }
+    }
+
+    public int getMaxSize() {
+        return _maxSize;
+    }
+
+    public void setMaxSize(int maxSize) {
+        _maxSize = (maxSize < 0) ? Integer.MAX_VALUE : maxSize;
+
+        if (_maxSize != Integer.MAX_VALUE) {
+            removeOverflow(_maxSize);
+        }
+    }
+
+    public boolean isFull() {
+        return size() >= _maxSize;
+    }
+
+    public void overflowRemoved(Object key, Object value) {
+    }
+
+    public void valueExpired(Object key) {
+    }
+
+    public void keyExpired(Object value) {
+    }
+
+    public void removeExpired() {
+        purge();
+    }
+
+    /**
+     *  Remove any entries over max size.
+     */
+    private void removeOverflow(int maxSize) {
+        Object key;
+
+        while (size() > maxSize) {
+            key = keySet().iterator().next();
+            overflowRemoved(key, remove(key));
+        }
+    }
+
+    protected void addMapping(int hashIndex, int hashCode, Object key,
+        Object value) {
+        if (_maxSize != Integer.MAX_VALUE) {
+            removeOverflow(_maxSize - 1);
+        }
+
+        super.addMapping(hashIndex, hashCode, key, value);
+    }
+
+    protected HashEntry createEntry(HashEntry next, int hashCode, Object key,
+        Object value) {
+        return new AccessibleEntry(this, next, hashCode, key, value);
+    }
+
+    protected void purge(Reference ref) {
+        // the logic for this method is taken from the original purge method
+        // we're overriding, with added logic to track the expired key/value
+        int index = hashIndex(ref.hashCode(), data.length);
+        AccessibleEntry entry = (AccessibleEntry) data[index];
+        AccessibleEntry prev = null;
+        Object key = null;
+        Object value = null;
+
+        while (entry != null) {
+            if (purge(entry, ref)) {
+                if (isHard(keyType)) {
+                    key = entry.key();
+                } else if (isHard(valueType)) {
+                    value = entry.value();
+                }
+
+                if (prev == null) {
+                    data[index] = entry.nextEntry();
+                } else {
+                    prev.setNextEntry(entry.nextEntry());
+                }
+
+                size--;
+
+                break;
+            }
+
+            prev = entry;
+            entry = entry.nextEntry();
+        }
+
+        if (key != null) {
+            valueExpired(key);
+        } else if (value != null) {
+            keyExpired(value);
+        }
+    }
+
+    /**
+     *  See the code for <code>ReferenceMap.ReferenceEntry.purge</code>.
+     */
+    private boolean purge(AccessibleEntry entry, Reference ref) {
+        boolean match = (!isHard(keyType) && (entry.key() == ref)) ||
+            (!isHard(valueType) && (entry.value() == ref));
+
+        if (match) {
+            if (!isHard(keyType)) {
+                ((Reference) entry.key()).clear();
+            }
+
+            if (!isHard(valueType)) {
+                ((Reference) entry.value()).clear();
+            } else if (purgeValues) {
+                entry.nullValue();
+            }
+        }
+
+        return match;
+    }
+
+    private static boolean isHard(int type) {
+        return type == org.apache.commons.collections.map.ReferenceMap.HARD;
+    }
+
+    protected void doWriteObject(ObjectOutputStream out)
+        throws IOException {
+        out.writeInt(_maxSize);
+        super.doWriteObject(out);
+    }
+
+    protected void doReadObject(ObjectInputStream in)
+        throws ClassNotFoundException, IOException {
+        _maxSize = in.readInt();
+        super.doReadObject(in);
+    }
+
+    /**
+     *  Extension of the base entry type that allows our outer class to access
+     *  protected state.
+     */
+    private static class AccessibleEntry extends ReferenceEntry {
+        public AccessibleEntry(
+            org.apache.commons.collections.map.AbstractReferenceMap map,
+            HashEntry next, int hashCode, Object key, Object value) {
+            super(map, next, hashCode, key, value);
+        }
+
+        public Object key() {
+            return key;
+        }
+
+        public Object value() {
+            return value;
+        }
+
+        public void nullValue() {
+            value = null;
+        }
+
+        public AccessibleEntry nextEntry() {
+            return (AccessibleEntry) next;
+        }
+
+        public void setNextEntry(AccessibleEntry next) {
+            this.next = next;
+        }
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashMap.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java?rev=417856&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java Wed Jun 28 12:34:33 2006
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.util;
+
+import org.apache.commons.collections.set.*;
+
+import java.io.*;
+
+import java.util.*;
+
+
+/**
+ *  <p>A set whose values may be stored as weak or soft references.</p>
+ *
+ *  @author Abe White
+ *  @nojavadoc */
+public class ReferenceHashSet implements Set, Serializable {
+    /**
+     *  Hard reference marker.
+      */
+    public static final int HARD = 0;
+
+    /**
+     *  Soft reference marker.
+      */
+    public static final int SOFT = 1;
+
+    /**
+     *  Weak reference marker.
+     */
+    public static final int WEAK = 2;
+    private static final Object DUMMY_VAL = new Object();
+    private final Set _set;
+
+    /**
+     *  Construct a set with the given reference type.
+     */
+    public ReferenceHashSet(int refType) {
+        if (refType == HARD) {
+            _set = new HashSet();
+        } else {
+            int mapRefType = (refType == WEAK)
+                ? org.apache.commons.collections.map.ReferenceMap.WEAK
+                : org.apache.commons.collections.map.ReferenceMap.SOFT;
+            _set = MapBackedSet.decorate(new org.apache.commons.collections.map.ReferenceMap(
+                        mapRefType,
+                        org.apache.commons.collections.map.ReferenceMap.HARD),
+                    DUMMY_VAL);
+        }
+    }
+
+    public boolean add(Object obj) {
+        return _set.add(obj);
+    }
+
+    public boolean addAll(Collection coll) {
+        return _set.addAll(coll);
+    }
+
+    public void clear() {
+        _set.clear();
+    }
+
+    public boolean contains(Object obj) {
+        return _set.contains(obj);
+    }
+
+    public boolean containsAll(Collection coll) {
+        return _set.containsAll(coll);
+    }
+
+    public boolean isEmpty() {
+        return _set.isEmpty();
+    }
+
+    public Iterator iterator() {
+        return _set.iterator();
+    }
+
+    public boolean remove(Object obj) {
+        return _set.remove(obj);
+    }
+
+    public boolean removeAll(Collection coll) {
+        return _set.removeAll(coll);
+    }
+
+    public boolean retainAll(Collection coll) {
+        return _set.retainAll(coll);
+    }
+
+    public int size() {
+        return _set.size();
+    }
+
+    public Object[] toArray() {
+        return _set.toArray();
+    }
+
+    public Object[] toArray(Object[] arr) {
+        return _set.toArray(arr);
+    }
+
+    public int hashCode() {
+        return _set.hashCode();
+    }
+
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof ReferenceHashSet) {
+            obj = ((ReferenceHashSet) obj)._set;
+        }
+
+        return _set.equals(obj);
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceMap.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceMap.java?rev=417856&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceMap.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceMap.java Wed Jun 28 12:34:33 2006
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.util;
+
+import java.util.*;
+
+
+/**
+ *  <p>A {@link Map} type that can hold its keys, values, or both with
+ *  weak or soft references.</p>
+ *
+ *  @author Abe White
+ */
+public interface ReferenceMap extends Map {
+    public static final int HARD = 0;
+    public static final int WEAK = 1;
+    public static final int SOFT = 2;
+
+    /**
+     *  Purge stale entries.
+     */
+    public void removeExpired();
+
+    /**
+     *  Overridable callback for when a key reference expires.
+     *
+     *  @param value the value for the expired key
+     */
+    public void keyExpired(Object value);
+
+    /**
+     *  Overridable callback for when a value reference expires.
+     *
+     *  @param key the key for the expired value
+     */
+    public void valueExpired(Object key);
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ReferenceMap.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ResourceBundleProvider.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ResourceBundleProvider.java?rev=417856&r1=415364&r2=417856&view=diff
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ResourceBundleProvider.java (original)
+++ incubator/openjpa/trunk/openjpa-lib/main/java/org/apache/openjpa/lib/util/ResourceBundleProvider.java Wed Jun 28 12:34:33 2006
@@ -15,23 +15,20 @@
  */
 package org.apache.openjpa.lib.util;
 
-
 import java.util.*;
 
 
 /**
- *	<p>A simple mechanism for looking up ResourceBundle instances
- *	across different potential sources.</p>
+ *  <p>A simple mechanism for looking up ResourceBundle instances
+ *  across different potential sources.</p>
  *
- *	@author	Stephen Kim
+ *  @author Stephen Kim
  */
-interface ResourceBundleProvider
-{
-	/**
-	 *	Find a ResourceBundle with the given name, locale, and class loader
-	 *	(which may be null).
-	 */
-	public ResourceBundle findResource (String name, Locale locale,
-		ClassLoader loader);
+interface ResourceBundleProvider {
+    /**
+     *  Find a ResourceBundle with the given name, locale, and class loader
+     *  (which may be null).
+     */
+    public ResourceBundle findResource(String name, Locale locale,
+        ClassLoader loader);
 }
-



Mime
View raw message