[Martin: Cc to commons-dev, that's why it is in english]

Hi,

I stumped over the following problem:

foo.bar =   aaa
foo.bar =   bbb, ccc


I expected a Configuration object to return for getVector("foo.bar") :

[ "aaa", "bbb", "ccc" ]

but I got

[ "aaa", "bbb, ccc" ]

Which basically sucks and is not the expected behaviour. Then I took
a look into BaseConfiguration (and recoiled in horror).

The attached patch(es) fix up the mess surrounding the internal store,
implement a Container wrapper for Vectors (as suggested in the comments)
and return the correct values for the scenario described above. These
are two patches, one is with additional commons-logging debugging
integrated but adds another jar to the dependencies.

As the comments suggest, that this container change should be post-1.0
(which IMHO would really be bad, the current code doesn't work correct
and is obfuscated) and the last changes are from August, I'd really like
to see this getting in _before_ 1.0 release.

As this seems to be Turbine spawned code, I hope, someone will check
this in (I'm using this with Turbine). Alternatively, someone might
simply give me karma on the repository (I'm a committer for Turbine so I
might be qualified for this. :-) ) 



        Regards
                Henning




-- 
Dipl.-Inf. (Univ.) Henning P. Schmiedehausen       -- Geschaeftsfuehrer
INTERMETA - Gesellschaft fuer Mehrwertdienste mbH     [EMAIL PROTECTED]

Am Schwabachgrund 22  Fon.: 09131 / 50654-0   [EMAIL PROTECTED]
D-91054 Buckenhof     Fax.: 09131 / 50654-20   
? lib
Index: project.xml
===================================================================
RCS file: /home/cvspublic/jakarta-commons-sandbox/configuration/project.xml,v
retrieving revision 1.10
diff -u -b -r1.10 project.xml
--- project.xml 28 Aug 2002 20:01:05 -0000      1.10
+++ project.xml 3 Dec 2002 11:17:10 -0000
@@ -76,6 +76,13 @@
       <organization>Multitask Consulting</organization>
     </developer>
 
+    <developer>
+      <name>Henning P. Schmiedehausen</name>
+      <id>henning</id>
+      <email>[EMAIL PROTECTED]</email>
+      <organization>INTERMETA - Gesellschaft fuer Mehrwertdienste mbH</organization>
+    </developer>
+
   </developers>
 
   <dependencies>
Index: src/java/org/apache/commons/configuration/BaseConfiguration.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-commons-sandbox/configuration/src/java/org/apache/commons/configuration/BaseConfiguration.java,v
retrieving revision 1.3
diff -u -b -r1.3 BaseConfiguration.java
--- src/java/org/apache/commons/configuration/BaseConfiguration.java    28 Aug 2002 
18:16:02 -0000      1.3
+++ src/java/org/apache/commons/configuration/BaseConfiguration.java    3 Dec 2002 
+11:17:10 -0000
@@ -57,6 +57,7 @@
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Properties;
 import java.util.StringTokenizer;
@@ -81,6 +82,7 @@
  * @author <a href="mailto:[EMAIL PROTECTED]";>Ilkka Priha</a>
  * @author <a href="mailto:[EMAIL PROTECTED]";>Jason van Zyl</a>
  * @author <a href="mailto:[EMAIL PROTECTED]";>Martin Poeschl</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]";>Henning P. Schmiedehausen</a>
  * @version $Id: BaseConfiguration.java,v 1.3 2002/08/28 18:16:02 mpoeschl Exp $
  */
 public class BaseConfiguration implements Configuration
@@ -115,50 +117,86 @@
      *
      * ["file", "classpath"]
      *
-     * @param key
-     * @param token
+     * @param key The Key to add the property to.
+     * @param token The Value to add.
      */
     public void addProperty(String key, Object token)
     {
+        List tokenAdd = null;
+
+        if (token instanceof String)
+        {
+            tokenAdd = processString((String) token);
+        }
+        else
+        {
+            tokenAdd = new Vector(1);
+            tokenAdd.add(token);
+        }
+
         Object o = store.get(key);
 
-        /*
-         *  $$$ GMJ
-         *  FIXME : post 1.0 release, we need to not assume
-         *  that a scalar is a String - it can be an Object
-         *  so we should make a little vector-like class
-         *  say, Foo that wraps (not extends Vector),
-         *  so we can do things like
-         *  if ( !( o instanceof Foo) )
-         *  so we know it's our 'vector' container
-         *
-         *  This applies throughout
-         */
-        if (o instanceof String)
-        {
-            Vector v = new Vector(2);
-            v.addElement(o);
-            v.addElement(token);
-            store.put(key, v);
+        if (o instanceof Container)
+        {
+            // There is already a container for our key in the config
+            // Simply add the new tokens 
+            for (Iterator it = tokenAdd.iterator(); it.hasNext(); )
+            {
+                ((Container) o).add(it.next());
+            }
+        }
+        else
+        {
+            // No Key at all or the token key is not a container.
+            Container c = new Container();
+
+            if (o != null)
+            {
+                // There is an element. Put it into the container
+                // at the first position
+                c.add(o);
+            }
+
+            // Now gobble up the supplied objects
+            for (Iterator it = tokenAdd.iterator(); it.hasNext(); )
+            {
+                c.add(it.next());
         }
-        else if (o instanceof Vector)
+
+            // Do we have a key? If not, we simply add either the container
+            // (If the element was a CSV) or the first element of the
+            // Container (if its size is 1)
+
+            if (o == null && c.size() == 1)
         {
-            ((Vector) o).addElement(token);
+                // No Key existed and only one got put into the container. Then
+                // add the key direct. Do not mess with the container
+                addPropertyDirect(key, c.get(0));
         }
         else
         {
-            /*
-             * This is the first time that we have seen request to place an
-             * object in the configuration with the key 'key'. So we just want
-             * to place it directly into the configuration ... but we are going
-             * to make a special exception for String objects that contain ","
-             * characters. We will take CSV lists and turn the list into a
-             * vector of Strings before placing it in the configuration.
-             * This is a concession for Properties and the like that cannot
-             * parse multiple same key values.
+                // Either a key already existed or there was a CSV supplied
+                // Add the Container to the Store
+                addPropertyDirect(key, c);
+            }
+        }
+    }
+
+    /**
+     * Returns a Vector of Strings built from the supplied
+     * String. Splits up CSV lists. If no commas are in the
+     * String, simply returns a Vector with the String as its
+     * first element
+     *
+     * @param token The String to tokenize
+     *
+     * @return A List of Strings
              */
-            if (token instanceof String &&
-                ((String) token).indexOf(PropertiesTokenizer.DELIMITER) > 0)
+    protected List processString(String token)
+    {
+        List retList = new ArrayList(2);
+
+        if (token.indexOf(PropertiesTokenizer.DELIMITER) > 0)
             {
                 PropertiesTokenizer tokenizer =
                     new PropertiesTokenizer((String) token);
@@ -166,27 +204,20 @@
                 while (tokenizer.hasMoreTokens())
                 {
                     String value = tokenizer.nextToken();
-
-                    /*
-                     * we know this is a string, so make sure it just goes in
-                     * rather than risking vectorization if it contains an
-                     * escaped comma
-                     */
-                    addStringProperty(key, value);
+                retList.add(value);
                 }
             }
             else
             {
-                /*
-                 * We want to keep track of the order the keys are parsed, or
-                 * dynamically entered into the configuration. So when we see a
-                 * key for the first time we will place it in an ArrayList so
-                 * that if a client class needs to perform operations with
-                 * configuration in a definite order it will be possible.
-                 */
-                addPropertyDirect(key, token);
-            }
+            retList.add(token);
         }
+
+        //
+        // We keep the sequence of the keys here and
+        // we also keep it in the Container. So the
+        // Keys are added to the store in the sequence that
+        // is given in the properties
+        return retList;
     }
 
     /**
@@ -209,49 +240,6 @@
     }
 
     /**
-     * Sets a string property w/o checking for commas - used internally when a
-     * property has been broken up into strings that could contain escaped
-     * commas to prevent the inadvertant vectorization.
-     */
-    private  void addStringProperty(String key, String token)
-    {
-        Object o = store.get(key);
-
-        /*
-         * $$$ GMJ
-         * FIXME : post 1.0 release, we need to not assume
-         * that a scalar is a String - it can be an Object
-         * so we should make a little vector-like class
-         * say, Foo that wraps (not extends Vector),
-         * so we can do things like
-         * if ( !( o instanceof Foo) )
-         * so we know it's our 'vector' container
-         *
-         * This applies throughout
-         */
-
-        /*
-         * do the usual thing - if we have a value and
-         * it's scalar, make a vector, otherwise add to the vector
-         */
-        if (o instanceof String)
-        {
-            Vector v = new Vector(2);
-            v.addElement(o);
-            v.addElement(token);
-            store.put(key, v);
-        }
-        else if (o instanceof Vector)
-        {
-            ((Vector) o).addElement(token);
-        }
-        else
-        {
-            addPropertyDirect(key, token);
-        }
-    }
-
-    /**
      * interpolate key names to handle ${key} stuff
      */
     protected String interpolate(String base)
@@ -502,7 +490,7 @@
      * @param key The configuration key.
      * @return The associated properties if key is found.
      * @exception ClassCastException is thrown if the key maps to an
-     * object that is not a String/Vector.
+     * object that is not a String/Vector of Strings.
      * @exception IllegalArgumentException if one of the tokens is
      * malformed (does not contain an equals sign).
      */
@@ -557,6 +545,16 @@
                 o = defaults.getProperty(key);
             }
         }
+
+        //
+        // We must never give a Container Object out. So if the
+        // Return Value is a Container, we fix it up to be a 
+        // Vector
+        //
+        if (o instanceof Container)
+        {
+            o = ((Container) o).asVector();
+        }
         return o;
     }
 
@@ -1207,9 +1205,9 @@
                 return interpolate(defaultValue);
             }
         }
-        else if (value instanceof Vector)
+        else if (value instanceof Container)
         {
-            return interpolate((String) ((Vector) value).get(0));
+            return interpolate((String) ((Container) value).get(0));
         }
         else
         {
@@ -1225,32 +1223,38 @@
      * @param key The configuration key.
      * @return The associated string array if key is found.
      * @exception ClassCastException is thrown if the key maps to an
-     * object that is not a String/Vector.
+     * object that is not a String/Vector of Strings.
      */
     public String[] getStringArray(String key)
     {
         Object value = store.get(key);
 
-        // What's your vector, Victor?
-        Vector vector;
+        String [] tokens;
+
         if (value instanceof String)
         {
-            vector = new Vector(1);
-            vector.addElement(interpolate((String) value));
+            tokens = new String [1];
+
+            tokens[0] = interpolate((String) value);
         }
-        else if (value instanceof Vector)
+        else if (value instanceof Container)
+        {
+            tokens = new String [((Container) value).size()];
+
+            for (int i = 0; i < tokens.length; i++)
         {
-            vector = (Vector) value;
+                tokens[i] = interpolate((String) ((Container) value).get(i));
+            }
         }
         else if (value == null)
         {
             if (defaults != null)
             {
-                return defaults.getStringArray(key);
+                tokens = defaults.getStringArray(key);
             }
             else
             {
-                return new String[0];
+                tokens = new String[0];
             }
         }
         else
@@ -1258,13 +1262,6 @@
             throw new ClassCastException(
                 '\'' + key + "' doesn't map to a String/Vector object");
         }
-
-        String[] tokens = new String[vector.size()];
-        for (int i = 0; i < tokens.length; i++)
-        {
-            tokens[i] = (String) vector.elementAt(i);
-        }
-
         return tokens;
     }
 
@@ -1293,35 +1290,35 @@
     public Vector getVector(String key, Vector defaultValue)
     {
         Object value = store.get(key);
+        Vector v = null;
 
-        if (value instanceof Vector)
+        if (value instanceof String)
         {
-            return (Vector) value;
+            v = new Vector(1);
+            v.addElement((String) value);
         }
-        else if (value instanceof String)
+        else if (value instanceof Container)
         {
-            Vector v = new Vector(1);
-            v.addElement((String) value);
-            store.put(key, v);
-            return v;
+            v = ((Container) value).asVector();
         }
         else if (value == null)
         {
             if (defaults != null)
             {
-                return defaults.getVector(key, defaultValue);
+                v = defaults.getVector(key, defaultValue);
             }
             else
             {
-                return ((defaultValue == null) ?
+                v = ((defaultValue == null) ?
                         new Vector() : defaultValue);
             }
         }
         else
         {
             throw new ClassCastException(
-                '\'' + key + "' doesn't map to a Vector object");
+                '\'' + key + "' doesn't map to a Vector object: " + value + ", a " + 
+value.getClass().getName());
         }
+        return v;
     }
 
     /**
@@ -1383,4 +1380,88 @@
             return buffer.toString().trim();
         }
     } // class PropertiesTokenizer
+
+
+    /**
+     * Private Wrapper class for Vector, so we can distinguish between 
+     * Vector objects and our container
+     */
+    class Container
+    {
+        /** We're wrapping a List object (A vector) */
+        private List l = null;
+
+        /**
+         * C'tor
+         */
+        public Container()
+        {
+            l = new Vector(2);
+        }
+
+        /**
+         * Add an Object to the Container
+         *
+         * @param o The Object
+         */
+        public  void add(Object o)
+        {
+            l.add(o);
+        }
+
+        /**
+         * Returns the current size of the Container
+         *
+         * @return The Number of elements in the container
+         */
+        public int size()
+        {
+            return l.size();
+        }
+
+        /**
+         * Returns the Element at an index
+         *
+         * @param index The Index
+         *
+         * @return The element at that index
+         */
+        public Object get(int index)
+        {
+            return l.get(index);
+        }
+
+        /**
+         * Returns an Iterator over the container
+         * objects
+         *
+         * @return An Iterator
+         */
+        public Iterator iterator()
+        {
+            return l.iterator();
+        }
+
+        /**
+         * Returns the Elements of the Container as
+         * a Vector. This is not the internal vector
+         * element but a shallow copy of the internal
+         * list. You may modify the returned list without
+         * modifying the container.
+         *
+         * @return A Vector containing the elements of
+         *         the Container.
+         */
+
+        public Vector asVector()
+        {
+            Vector v = new Vector(l.size());
+
+            for (Iterator it = l.iterator(); it.hasNext(); )
+            {
+                v.add(it.next());
+            }
+            return v;
+        }
+    }
 }
? lib
Index: project.xml
===================================================================
RCS file: /home/cvspublic/jakarta-commons-sandbox/configuration/project.xml,v
retrieving revision 1.10
diff -u -b -r1.10 project.xml
--- project.xml 28 Aug 2002 20:01:05 -0000      1.10
+++ project.xml 3 Dec 2002 11:17:10 -0000
@@ -76,6 +76,13 @@
       <organization>Multitask Consulting</organization>
     </developer>
 
+    <developer>
+      <name>Henning P. Schmiedehausen</name>
+      <id>henning</id>
+      <email>[EMAIL PROTECTED]</email>
+      <organization>INTERMETA - Gesellschaft fuer Mehrwertdienste mbH</organization>
+    </developer>
+
   </developers>
 
   <dependencies>
Index: build.xml
===================================================================
RCS file: /home/cvspublic/jakarta-commons-sandbox/configuration/build.xml,v
retrieving revision 1.3
diff -u -b -r1.3 build.xml
--- build.xml   28 Aug 2002 19:45:27 -0000      1.3
+++ build.xml   3 Dec 2002 11:13:20 -0000
@@ -130,6 +130,7 @@
     <get dest="lib/commons-collections-2.0.jar" usetimestamp="true" 
ignoreerrors="true" 
src="http://www.ibiblio.org/maven/commons-collections/jars/commons-collections-2.0.jar";></get>
     <get dest="lib/commons-lang-1.0-b1.jar" usetimestamp="true" ignoreerrors="true" 
src="http://www.ibiblio.org/maven/commons-lang/jars/commons-lang-1.0-b1.jar";></get>
     <get dest="lib/junit-3.7.jar" usetimestamp="true" ignoreerrors="true" 
src="http://www.ibiblio.org/maven/junit/jars/junit-3.7.jar";></get>
+    <get dest="lib/commons-logging-1.0.2.jar" usetimestamp="true" ignoreerrors="true" 
+src="http://www.ibiblio.org/maven/commons-logging/jars/commons-logging-1.0.2.jar";></get>
   
   </target>
 
Index: src/java/org/apache/commons/configuration/BaseConfiguration.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-commons-sandbox/configuration/src/java/org/apache/commons/configuration/BaseConfiguration.java,v
retrieving revision 1.3
diff -u -b -r1.3 BaseConfiguration.java
--- src/java/org/apache/commons/configuration/BaseConfiguration.java    28 Aug 2002 
18:16:02 -0000      1.3
+++ src/java/org/apache/commons/configuration/BaseConfiguration.java    3 Dec 2002 
+11:13:20 -0000
@@ -57,11 +57,15 @@
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Properties;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 /**
  * Basic configuration classe. Stores the configuration data but does not
  * provide any load or save functions. If you want to load your Configuration
@@ -81,6 +85,7 @@
  * @author <a href="mailto:[EMAIL PROTECTED]";>Ilkka Priha</a>
  * @author <a href="mailto:[EMAIL PROTECTED]";>Jason van Zyl</a>
  * @author <a href="mailto:[EMAIL PROTECTED]";>Martin Poeschl</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]";>Henning P. Schmiedehausen</a>
  * @version $Id: BaseConfiguration.java,v 1.3 2002/08/28 18:16:02 mpoeschl Exp $
  */
 public class BaseConfiguration implements Configuration
@@ -91,6 +96,9 @@
     /** stores the configuration key-value pairs */
     protected Configuration defaults = null;
 
+    /** Logging */
+    private static Log log = LogFactory.getLog(BaseConfiguration.class);
+
     /**
      * These are the keys in the order they listed in the configuration file.
      * This is useful when you wish to perform operations with configuration
@@ -115,50 +123,88 @@
      *
      * ["file", "classpath"]
      *
-     * @param key
-     * @param token
+     * @param key The Key to add the property to.
+     * @param token The Value to add.
      */
     public void addProperty(String key, Object token)
     {
+        log.debug("doAddProperty(" + key + ", " + token + ")");
+
+        List tokenAdd = null;
+
+        if (token instanceof String)
+        {
+            tokenAdd = processString((String) token);
+        }
+        else
+        {
+            tokenAdd = new Vector(1);
+            tokenAdd.add(token);
+        }
+
         Object o = store.get(key);
 
-        /*
-         *  $$$ GMJ
-         *  FIXME : post 1.0 release, we need to not assume
-         *  that a scalar is a String - it can be an Object
-         *  so we should make a little vector-like class
-         *  say, Foo that wraps (not extends Vector),
-         *  so we can do things like
-         *  if ( !( o instanceof Foo) )
-         *  so we know it's our 'vector' container
-         *
-         *  This applies throughout
-         */
-        if (o instanceof String)
-        {
-            Vector v = new Vector(2);
-            v.addElement(o);
-            v.addElement(token);
-            store.put(key, v);
+        if (o instanceof Container)
+        {
+            // There is already a container for our key in the config
+            // Simply add the new tokens 
+            for (Iterator it = tokenAdd.iterator(); it.hasNext(); )
+            {
+                ((Container) o).add(it.next());
         }
-        else if (o instanceof Vector)
+        }
+        else
+        {
+            // No Key at all or the token key is not a container.
+            Container c = new Container();
+
+            if (o != null)
         {
-            ((Vector) o).addElement(token);
+                // There is an element. Put it into the container
+                // at the first position
+                c.add(o);
+            }
+
+            // Now gobble up the supplied objects
+            for (Iterator it = tokenAdd.iterator(); it.hasNext(); )
+            {
+                c.add(it.next());
+            }
+
+            // Do we have a key? If not, we simply add either the container
+            // (If the element was a CSV) or the first element of the
+            // Container (if its size is 1)
+
+            if (o == null && c.size() == 1)
+            {
+                // No Key existed and only one got put into the container. Then
+                // add the key direct. Do not mess with the container
+                addPropertyDirect(key, c.get(0));
         }
         else
         {
-            /*
-             * This is the first time that we have seen request to place an
-             * object in the configuration with the key 'key'. So we just want
-             * to place it directly into the configuration ... but we are going
-             * to make a special exception for String objects that contain ","
-             * characters. We will take CSV lists and turn the list into a
-             * vector of Strings before placing it in the configuration.
-             * This is a concession for Properties and the like that cannot
-             * parse multiple same key values.
+                // Either a key already existed or there was a CSV supplied
+                // Add the Container to the Store
+                addPropertyDirect(key, c);
+            }
+        }
+    }
+
+    /**
+     * Returns a Vector of Strings built from the supplied
+     * String. Splits up CSV lists. If no commas are in the
+     * String, simply returns a Vector with the String as its
+     * first element
+     *
+     * @param token The String to tokenize
+     *
+     * @return A List of Strings
              */
-            if (token instanceof String &&
-                ((String) token).indexOf(PropertiesTokenizer.DELIMITER) > 0)
+    protected List processString(String token)
+    {
+        List retList = new ArrayList(2);
+
+        if (token.indexOf(PropertiesTokenizer.DELIMITER) > 0)
             {
                 PropertiesTokenizer tokenizer =
                     new PropertiesTokenizer((String) token);
@@ -166,27 +212,20 @@
                 while (tokenizer.hasMoreTokens())
                 {
                     String value = tokenizer.nextToken();
-
-                    /*
-                     * we know this is a string, so make sure it just goes in
-                     * rather than risking vectorization if it contains an
-                     * escaped comma
-                     */
-                    addStringProperty(key, value);
+                retList.add(value);
                 }
             }
             else
             {
-                /*
-                 * We want to keep track of the order the keys are parsed, or
-                 * dynamically entered into the configuration. So when we see a
-                 * key for the first time we will place it in an ArrayList so
-                 * that if a client class needs to perform operations with
-                 * configuration in a definite order it will be possible.
-                 */
-                addPropertyDirect(key, token);
-            }
+            retList.add(token);
         }
+
+        //
+        // We keep the sequence of the keys here and
+        // we also keep it in the Container. So the
+        // Keys are added to the store in the sequence that
+        // is given in the properties
+        return retList;
     }
 
     /**
@@ -209,49 +248,6 @@
     }
 
     /**
-     * Sets a string property w/o checking for commas - used internally when a
-     * property has been broken up into strings that could contain escaped
-     * commas to prevent the inadvertant vectorization.
-     */
-    private  void addStringProperty(String key, String token)
-    {
-        Object o = store.get(key);
-
-        /*
-         * $$$ GMJ
-         * FIXME : post 1.0 release, we need to not assume
-         * that a scalar is a String - it can be an Object
-         * so we should make a little vector-like class
-         * say, Foo that wraps (not extends Vector),
-         * so we can do things like
-         * if ( !( o instanceof Foo) )
-         * so we know it's our 'vector' container
-         *
-         * This applies throughout
-         */
-
-        /*
-         * do the usual thing - if we have a value and
-         * it's scalar, make a vector, otherwise add to the vector
-         */
-        if (o instanceof String)
-        {
-            Vector v = new Vector(2);
-            v.addElement(o);
-            v.addElement(token);
-            store.put(key, v);
-        }
-        else if (o instanceof Vector)
-        {
-            ((Vector) o).addElement(token);
-        }
-        else
-        {
-            addPropertyDirect(key, token);
-        }
-    }
-
-    /**
      * interpolate key names to handle ${key} stuff
      */
     protected String interpolate(String base)
@@ -502,7 +498,7 @@
      * @param key The configuration key.
      * @return The associated properties if key is found.
      * @exception ClassCastException is thrown if the key maps to an
-     * object that is not a String/Vector.
+     * object that is not a String/Vector of Strings.
      * @exception IllegalArgumentException if one of the tokens is
      * malformed (does not contain an equals sign).
      */
@@ -557,6 +553,16 @@
                 o = defaults.getProperty(key);
             }
         }
+
+        //
+        // We must never give a Container Object out. So if the
+        // Return Value is a Container, we fix it up to be a 
+        // Vector
+        //
+        if (o instanceof Container)
+        {
+            o = ((Container) o).asVector();
+        }
         return o;
     }
 
@@ -1207,9 +1213,9 @@
                 return interpolate(defaultValue);
             }
         }
-        else if (value instanceof Vector)
+        else if (value instanceof Container)
         {
-            return interpolate((String) ((Vector) value).get(0));
+            return interpolate((String) ((Container) value).get(0));
         }
         else
         {
@@ -1225,32 +1231,38 @@
      * @param key The configuration key.
      * @return The associated string array if key is found.
      * @exception ClassCastException is thrown if the key maps to an
-     * object that is not a String/Vector.
+     * object that is not a String/Vector of Strings.
      */
     public String[] getStringArray(String key)
     {
         Object value = store.get(key);
 
-        // What's your vector, Victor?
-        Vector vector;
+        String [] tokens;
+
         if (value instanceof String)
         {
-            vector = new Vector(1);
-            vector.addElement(interpolate((String) value));
+            tokens = new String [1];
+
+            tokens[0] = interpolate((String) value);
         }
-        else if (value instanceof Vector)
+        else if (value instanceof Container)
         {
-            vector = (Vector) value;
+            tokens = new String [((Container) value).size()];
+
+            for (int i = 0; i < tokens.length; i++)
+            {
+                tokens[i] = interpolate((String) ((Container) value).get(i));
+            }
         }
         else if (value == null)
         {
             if (defaults != null)
             {
-                return defaults.getStringArray(key);
+                tokens = defaults.getStringArray(key);
             }
             else
             {
-                return new String[0];
+                tokens = new String[0];
             }
         }
         else
@@ -1258,13 +1270,6 @@
             throw new ClassCastException(
                 '\'' + key + "' doesn't map to a String/Vector object");
         }
-
-        String[] tokens = new String[vector.size()];
-        for (int i = 0; i < tokens.length; i++)
-        {
-            tokens[i] = (String) vector.elementAt(i);
-        }
-
         return tokens;
     }
 
@@ -1293,35 +1298,51 @@
     public Vector getVector(String key, Vector defaultValue)
     {
         Object value = store.get(key);
+        Vector v = null;
 
-        if (value instanceof Vector)
+        if (log.isDebugEnabled())
         {
-            return (Vector) value;
+            if (value != null)
+            {
+                log.debug("Found a " + value.getClass().getName() + " for key " + 
+key);
         }
-        else if (value instanceof String)
+            else
         {
-            Vector v = new Vector(1);
+                log.debug("Found null for key " + key);
+            }
+        }
+
+        if (value instanceof String)
+        {
+            log.debug("Value is a String");
+            v = new Vector(1);
             v.addElement((String) value);
-            store.put(key, v);
-            return v;
+        }
+        else if (value instanceof Container)
+        {
+            log.debug("Value is a Container");
+            v = ((Container) value).asVector();
         }
         else if (value == null)
         {
+            log.debug("Value is null");
+
             if (defaults != null)
             {
-                return defaults.getVector(key, defaultValue);
+                v = defaults.getVector(key, defaultValue);
             }
             else
             {
-                return ((defaultValue == null) ?
+                v = ((defaultValue == null) ?
                         new Vector() : defaultValue);
             }
         }
         else
         {
             throw new ClassCastException(
-                '\'' + key + "' doesn't map to a Vector object");
+                '\'' + key + "' doesn't map to a Vector object: " + value + ", a " + 
+value.getClass().getName());
         }
+        return v;
     }
 
     /**
@@ -1383,4 +1404,88 @@
             return buffer.toString().trim();
         }
     } // class PropertiesTokenizer
+
+
+    /**
+     * Private Wrapper class for Vector, so we can distinguish between 
+     * Vector objects and our container
+     */
+    class Container
+    {
+        /** We're wrapping a List object (A vector) */
+        private List l = null;
+
+        /**
+         * C'tor
+         */
+        public Container()
+        {
+            l = new Vector(2);
+        }
+
+        /**
+         * Add an Object to the Container
+         *
+         * @param o The Object
+         */
+        public  void add(Object o)
+        {
+            l.add(o);
+        }
+
+        /**
+         * Returns the current size of the Container
+         *
+         * @return The Number of elements in the container
+         */
+        public int size()
+        {
+            return l.size();
+        }
+
+        /**
+         * Returns the Element at an index
+         *
+         * @param index The Index
+         *
+         * @return The element at that index
+         */
+        public Object get(int index)
+        {
+            return l.get(index);
+        }
+
+        /**
+         * Returns an Iterator over the container
+         * objects
+         *
+         * @return An Iterator
+         */
+        public Iterator iterator()
+        {
+            return l.iterator();
+        }
+
+        /**
+         * Returns the Elements of the Container as
+         * a Vector. This is not the internal vector
+         * element but a shallow copy of the internal
+         * list. You may modify the returned list without
+         * modifying the container.
+         *
+         * @return A Vector containing the elements of
+         *         the Container.
+         */
+
+        public Vector asVector()
+        {
+            Vector v = new Vector(l.size());
+
+            for (Iterator it = l.iterator(); it.hasNext(); )
+            {
+                v.add(it.next());
+            }
+            return v;
+        }
+    }
 }

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to