You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@turbine.apache.org by mp...@apache.org on 2002/02/04 12:31:34 UTC

cvs commit: jakarta-turbine-stratum/src/java/org/apache/stratum/configuration BaseConfiguration.java package.html Configuration.java PropertiesConfiguration.java XmlConfiguration.java AbstractConfiguration.java

mpoeschl    02/02/04 03:31:34

  Modified:    src/java/org/apache/stratum/configuration Configuration.java
                        PropertiesConfiguration.java XmlConfiguration.java
  Added:       src/java/org/apache/stratum/configuration
                        BaseConfiguration.java package.html
  Removed:     src/java/org/apache/stratum/configuration
                        AbstractConfiguration.java
  Log:
  new configuration package based on ExtendedProperties
  
  Revision  Changes    Path
  1.2       +97 -19    jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/Configuration.java
  
  Index: Configuration.java
  ===================================================================
  RCS file: /home/cvs/jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/Configuration.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Configuration.java	5 Jan 2002 03:22:59 -0000	1.1
  +++ Configuration.java	4 Feb 2002 11:31:34 -0000	1.2
  @@ -1,29 +1,107 @@
   package org.apache.stratum.configuration;
   
  +/* ====================================================================
  + * The Apache Software License, Version 1.1
  + *
  + * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
  + * reserved.
  + *
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + *
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + *
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in
  + *    the documentation and/or other materials provided with the
  + *    distribution.
  + *
  + * 3. The end-user documentation included with the redistribution,
  + *    if any, must include the following acknowledgment:
  + *       "This product includes software developed by the
  + *        Apache Software Foundation (http://www.apache.org/)."
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
  + *
  + * 4. The names "Apache" and "Apache Software Foundation" and
  + *    "Apache Turbine" must not be used to endorse or promote products
  + *    derived from this software without prior written permission. For
  + *    written permission, please contact apache@apache.org.
  + *
  + * 5. Products derived from this software may not be called "Apache",
  + *    "Apache Turbine", nor may "Apache" appear in their name, without
  + *    prior written permission of the Apache Software Foundation.
  + *
  + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + * ====================================================================
  + *
  + * This software consists of voluntary contributions made by many
  + * individuals on behalf of the Apache Software Foundation.  For more
  + * information on the Apache Software Foundation, please see
  + * <http://www.apache.org/>.
  + */
  +
   import java.util.Iterator;
  +import java.util.Properties;
   import java.util.Vector;
   
  -// The general idea here is to make something that will work like
  -// our extended properties and be compatible with the preferences
  -// API if at all possible.
  -
  +/**
  + * Configuration interface.
  + * The general idea here is to make something that will work like our
  + * extended properties and be compatible with the preferences API if at all
  + * possible.
  + *
  + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
  + * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
  + * @version $Id: Configuration.java,v 1.2 2002/02/04 11:31:34 mpoeschl Exp $
  + */
   public interface Configuration
  -{    
  -    Vector getVector(String key);
  -    String getString(String key);
  +{
  +    Configuration subset(String prefix);
  +
  +    boolean isEmpty();
  +    boolean containsKey(String key);
  +    void addProperty(String key, Object value);
  +    void setProperty(String key, Object value);
  +    void clearProperty(String key);
       Iterator getKeys(String key);
  -    int getInt(String key, int defaultValue);
  -    
  +    Iterator getKeys();
  +    Properties getProperties();
  +
       // We probably want to at least try to be compatible with
       // the new preferences API.
  -    
  -    // Iterator getKeys()
  -    
  -    // byte getByte(String key);
  -    // short getShort(String key);
  -    // long getLong(String key);
  -    
  -    // float getFloat(String key);
  -    // boolean getBoolean(String key);
  -    // double getDouble(String key);
  +
  +    boolean getBoolean(String key);
  +    boolean getBoolean(String key, boolean defaultValue);
  +//    Boolean getBoolean(String key, Boolean defaultValue);
  +    byte getByte(String key);
  +    double getDouble(String key);
  +    float getFloat(String key);
  +    int getInt(String key, int defaultValue);
  +    Integer getInteger(String key, Integer defaultValue);
  +    long getLong(String key);
  +    long getLong(String key, long defaultValue);
  +//    Long getLong(String key, Long defaultValue);
  +    short getShort(String key);
  +    String getString(String key);
  +    String getString(String key, String defaultValue);
  +    String[] getStringArray(String key);
  +    Vector getVector(String key);
  +    Vector getVector(String key, Vector defaultValue);
  +
  +
  +
   }
  
  
  
  1.2       +402 -3    jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/PropertiesConfiguration.java
  
  Index: PropertiesConfiguration.java
  ===================================================================
  RCS file: /home/cvs/jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/PropertiesConfiguration.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PropertiesConfiguration.java	18 Jan 2002 22:26:05 -0000	1.1
  +++ PropertiesConfiguration.java	4 Feb 2002 11:31:34 -0000	1.2
  @@ -1,9 +1,408 @@
   package org.apache.stratum.configuration;
   
  +/* ====================================================================
  + * The Apache Software License, Version 1.1
  + *
  + * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
  + * reserved.
  + *
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + *
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + *
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in
  + *    the documentation and/or other materials provided with the
  + *    distribution.
  + *
  + * 3. The end-user documentation included with the redistribution,
  + *    if any, must include the following acknowledgment:
  + *       "This product includes software developed by the
  + *        Apache Software Foundation (http://www.apache.org/)."
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
  + *
  + * 4. The names "Apache" and "Apache Software Foundation" and
  + *    "Apache Turbine" must not be used to endorse or promote products
  + *    derived from this software without prior written permission. For
  + *    written permission, please contact apache@apache.org.
  + *
  + * 5. Products derived from this software may not be called "Apache",
  + *    "Apache Turbine", nor may "Apache" appear in their name, without
  + *    prior written permission of the Apache Software Foundation.
  + *
  + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + * ====================================================================
  + *
  + * This software consists of voluntary contributions made by many
  + * individuals on behalf of the Apache Software Foundation.  For more
  + * information on the Apache Software Foundation, please see
  + * <http://www.apache.org/>.
  + */
  +
  +import java.io.File;
  +import java.io.FileInputStream;
  +import java.io.InputStream;
  +import java.io.InputStreamReader;
  +import java.io.IOException;
  +import java.io.LineNumberReader;
  +import java.io.Reader;
  +import java.io.UnsupportedEncodingException;
  +
   // Borrow a lot of the code from ExtendedProperties, but leave
   // the resource handling to the resources package.
   
  -public class PropertiesConfiguration
  -    extends AbstractConfiguration
  -{    
  +/**
  + * loads the configuration from a properties file. <p>
  + *
  + * <p>The Extended Properties syntax is explained here:
  + *
  + * <ul>
  + *  <li>
  + *   Each property has the syntax <code>key = value</code>
  + *  </li>
  + *  <li>
  + *   The <i>key</i> may use any character but the equal sign '='.
  + *  </li>
  + *  <li>
  + *   <i>value</i> may be separated on different lines if a backslash
  + *   is placed at the end of the line that continues below.
  + *  </li>
  + *  <li>
  + *   If <i>value</i> is a list of strings, each token is separated
  + *   by a comma ','.
  + *  </li>
  + *  <li>
  + *   Commas in each token are escaped placing a backslash right before
  + *   the comma.
  + *  </li>
  + *  <li>
  + *   If a <i>key</i> is used more than once, the values are appended
  + *   like if they were on the same line separated with commas.
  + *  </li>
  + *  <li>
  + *   Blank lines and lines starting with character '#' are skipped.
  + *  </li>
  + *  <li>
  + *   If a property is named "include" (or whatever is defined by
  + *   setInclude() and getInclude() and the value of that property is
  + *   the full path to a file on disk, that file will be included into
  + *   the ConfigurationsRepository. You can also pull in files relative
  + *   to the parent configuration file. So if you have something
  + *   like the following:
  + *
  + *   include = additional.properties
  + *
  + *   Then "additional.properties" is expected to be in the same
  + *   directory as the parent configuration file.
  + *
  + *   Duplicate name values will be replaced, so be careful.
  + *
  + *  </li>
  + * </ul>
  + *
  + * <p>Here is an example of a valid extended properties file:
  + *
  + * <p><pre>
  + *      # lines starting with # are comments
  + *
  + *      # This is the simplest property
  + *      key = value
  + *
  + *      # A long property may be separated on multiple lines
  + *      longvalue = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
  + *                  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  + *
  + *      # This is a property with many tokens
  + *      tokens_on_a_line = first token, second token
  + *
  + *      # This sequence generates exactly the same result
  + *      tokens_on_multiple_lines = first token
  + *      tokens_on_multiple_lines = second token
  + *
  + *      # commas may be escaped in tokens
  + *      commas.excaped = Hi\, what'up?
  + * </pre>
  + *
  + * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
  + * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
  + * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a>
  + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
  + * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
  + * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
  + * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
  + * @author <a href="mailto:ipriha@surfeu.fi">Ilkka Priha</a>
  + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
  + * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
  + * @version $Id: PropertiesConfiguration.java,v 1.2 2002/02/04 11:31:34 mpoeschl Exp $
  + */
  +public class PropertiesConfiguration extends BaseConfiguration
  +{
  +
  +    /** File separator. */
  +    protected String fileSeparator = System.getProperty("file.separator");
  +
  +    /**
  +     * Base path of the configuration file used to create this Configuration
  +     * object.
  +     */
  +    protected String basePath;
  +
  +    /**
  +     * This is the name of the property that can point to other
  +     * properties file for including other properties files.
  +     */
  +    protected static String include = "include";
  +
  +
  +    /**
  +     * Creates an empty Configuration
  +     */
  +    public PropertiesConfiguration()
  +    {
  +    }
  +
  +    /**
  +     * Creates and loads the extended properties from the specified file.
  +     *
  +     * @param file A String.
  +     * @exception IOException.
  +     */
  +    public PropertiesConfiguration(String file) throws IOException
  +    {
  +        this(file, null);
  +    }
  +
  +    /**
  +     * Creates and loads the extended properties from the specified file.
  +     *
  +     * @param file A String.
  +     * @exception IOException.
  +     */
  +    public PropertiesConfiguration(String file, String defaultFile)
  +        throws IOException
  +    {
  +//        this.file = file;
  +
  +        basePath = new File(file).getAbsolutePath();
  +        basePath = basePath.substring(0, basePath.lastIndexOf(fileSeparator) + 1);
  +
  +        this.load(new FileInputStream(file));
  +
  +        if (defaultFile != null)
  +        {
  +            defaults = (BaseConfiguration)
  +                    new PropertiesConfiguration(defaultFile);
  +        }
  +    }
  +
  +    /**
  +     * Load the properties from the given input stream.
  +     *
  +     * @param input An InputStream.
  +     * @exception IOException.
  +     */
  +    public void load(InputStream input) throws IOException
  +    {
  +        load(input, null);
  +    }
  +
  +    /**
  +     * Load the properties from the given input stream and using the specified
  +     * encoding.
  +     *
  +     * @param input An InputStream.
  +     * @param enc An encoding.
  +     * @exception IOException.
  +     */
  +    public synchronized void load(InputStream input, String enc)
  +            throws IOException
  +    {
  +        PropertiesReader reader = null;
  +        if (enc != null)
  +        {
  +            try
  +            {
  +                reader =
  +                    new PropertiesReader(new InputStreamReader(input, enc));
  +            }
  +            catch (UnsupportedEncodingException e)
  +            {
  +                // Get one with the default encoding...
  +            }
  +        }
  +
  +        if (reader == null)
  +        {
  +            reader =
  +                new PropertiesReader(new InputStreamReader(input));
  +        }
  +
  +        try
  +        {
  +            while (true)
  +            {
  +                String line = reader.readProperty();
  +                int equalSign = line.indexOf('=');
  +
  +                if (equalSign > 0)
  +                {
  +                    String key = line.substring(0, equalSign).trim();
  +                    String value = line.substring(equalSign + 1).trim();
  +
  +                    /*
  +                     * Configure produces lines like this ... just
  +                     * ignore them.
  +                     */
  +                    if ("".equals(value))
  +                        continue;
  +
  +                    if (getInclude() != null &&
  +                        key.equalsIgnoreCase(getInclude()))
  +                    {
  +                        /*
  +                         * Recursively load properties files.
  +                         */
  +                        File file = null;
  +
  +                        if (value.startsWith(fileSeparator))
  +                        {
  +                            /*
  +                             * We have an absolute path so we'll
  +                             * use this.
  +                             */
  +                            file = new File(value);
  +                        }
  +                        else
  +                        {
  +                            /*
  +                             * We have a relative path, and we have
  +                             * two possible forms here. If we have the
  +                             * "./" form then just strip that off first
  +                             * before continuing.
  +                             */
  +                            if (value.startsWith("." + fileSeparator))
  +                            {
  +                                value = value.substring(2);
  +                            }
  +
  +                            file = new File(basePath + value);
  +                        }
  +
  +                        if (file != null && file.exists() && file.canRead())
  +                        {
  +                            load ( new FileInputStream(file));
  +                        }
  +                    }
  +                    else
  +                    {
  +                        addProperty(key,value);
  +                    }
  +                }
  +            }
  +        }
  +        catch (NullPointerException e)
  +        {
  +            /*
  +             * Should happen only when EOF is reached.
  +             */
  +            return;
  +        }
  +    }
  +
  +    /**
  +     * Gets the property value for including other properties files.
  +     * By default it is "include".
  +     *
  +     * @return A String.
  +     */
  +    public String getInclude()
  +    {
  +        return this.include;
  +    }
  +
  +    /**
  +     * Sets the property value for including other properties files.
  +     * By default it is "include".
  +     *
  +     * @param inc A String.
  +     */
  +    public void setInclude(String inc)
  +    {
  +        this.include = inc;
  +    }
  +
  +
  +    /**
  +     * This class is used to read properties lines.  These lines do
  +     * not terminate with new-line chars but rather when there is no
  +     * backslash sign a the end of the line.  This is used to
  +     * concatenate multiple lines for readability.
  +     */
  +    class PropertiesReader extends LineNumberReader
  +    {
  +        /**
  +         * Constructor.
  +         *
  +         * @param reader A Reader.
  +         */
  +        public PropertiesReader(Reader reader)
  +        {
  +            super(reader);
  +        }
  +
  +        /**
  +         * Read a property.
  +         *
  +         * @return A String.
  +         * @exception IOException.
  +         */
  +        public String readProperty() throws IOException
  +        {
  +            StringBuffer buffer = new StringBuffer();
  +
  +            try
  +            {
  +                while (true)
  +                {
  +                    String line = readLine().trim();
  +                    if ((line.length() != 0) && (line.charAt(0) != '#'))
  +                    {
  +                        if (line.endsWith("\\"))
  +                        {
  +                            line = line.substring(0, line.length() - 1);
  +                            buffer.append(line);
  +                        }
  +                        else
  +                        {
  +                            buffer.append(line);
  +                            break;
  +                        }
  +                    }
  +                }
  +            }
  +            catch (NullPointerException e)
  +            {
  +                return null;
  +            }
  +
  +            return buffer.toString();
  +        }
  +    } // class PropertiesReader
  +
  +
   }
  
  
  
  1.2       +3 -3      jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/XmlConfiguration.java
  
  Index: XmlConfiguration.java
  ===================================================================
  RCS file: /home/cvs/jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/XmlConfiguration.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- XmlConfiguration.java	18 Jan 2002 22:26:05 -0000	1.1
  +++ XmlConfiguration.java	4 Feb 2002 11:31:34 -0000	1.2
  @@ -1,5 +1,6 @@
   package org.apache.stratum.configuration;
   
  +
   /**
    * <configuration>
    *   <entries>
  @@ -11,7 +12,6 @@
    * </configuration>
    *
    */
  -public class XmlConfiguration
  -    extends AbstractConfiguration
  -{    
  +public class XmlConfiguration extends BaseConfiguration
  +{
   }
  
  
  
  1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/BaseConfiguration.java
  
  Index: BaseConfiguration.java
  ===================================================================
  package org.apache.stratum.configuration;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Turbine" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.util.ArrayList;
  import java.util.Hashtable;
  import java.util.Iterator;
  import java.util.NoSuchElementException;
  import java.util.Properties;
  import java.util.StringTokenizer;
  import java.util.Vector;
  
  /**
   * Basic configuration classe. Stores the configuration data but does not
   * provide any load or save functions. If you want to load your Configuration
   * from a file use PropertiesConfiguration or XmlConfiguration.
   *
   * This class extends normal Java properties by adding the possibility
   * to use the same key many times concatenating the value strings
   * instead of overwriting them.
   *
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
   * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a>
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
   * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
   * @author <a href="mailto:ipriha@surfeu.fi">Ilkka Priha</a>
   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
   * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
   * @version $Id: BaseConfiguration.java,v 1.1 2002/02/04 11:31:34 mpoeschl Exp $
   */
  public class BaseConfiguration
  {
  
      /* stores the configuration key-value pairs */
      private Hashtable store = new Hashtable();
  
      /* stores the configuration key-value pairs */
      protected BaseConfiguration defaults = null;
  
      /**
       * These are the keys in the order they listed in the configuration file.
       * This is useful when you wish to perform operations with configuration
       * information in a particular order.
       */
      protected ArrayList keysAsListed = new ArrayList();
  
      protected final static String START_TOKEN = "${";
      protected final static String END_TOKEN = "}";
  
      /**
       * Add a property to the configuration. If it already exists then the value
       * stated here will be added to the configuration entry. For example, if
       *
       * resource.loader = file
       *
       * is already present in the configuration and you
       *
       * addProperty("resource.loader", "classpath")
       *
       * Then you will end up with a Vector like the following:
       *
       * ["file", "classpath"]
       *
       * @param String key
       * @param String value
       */
      public void addProperty(String key, Object 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);
          }
          else if (o instanceof Vector)
          {
              ((Vector) o).addElement(token);
          }
          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.
               */
              if (token instanceof String &&
                  ((String)token).indexOf(PropertiesTokenizer.DELIMITER) > 0)
              {
                  PropertiesTokenizer tokenizer =
                      new PropertiesTokenizer((String)token);
  
                  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);
                  }
              }
              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);
              }
          }
      }
  
      /**
       * Adds a key/value pair to the map.  This routine does no magic morphing.
       * It ensures the keylist is maintained
       *
       * @param key key to use for mapping
       * @param obj object to store
       */
      protected void addPropertyDirect(String key, Object obj)
      {
          // safety check
          if(! store.containsKey(key))
          {
              keysAsListed.add(key);
          }
  
          // and the value
          store.put(key, obj);
      }
  
      /**
       * 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)
      {
          if (base == null)
          {
              return null;
          }
  
          int begin = -1;
          int end = -1;
          int prec = 0 - END_TOKEN.length();
          String variable = null;
          StringBuffer result = new StringBuffer();
  
          // FIXME: we should probably allow the escaping of the start token
          while ( ((begin = base.indexOf(START_TOKEN, prec + END_TOKEN.length())) >-1)
                  && ((end = base.indexOf(END_TOKEN, begin)) > -1) )
          {
              result.append(base.substring(prec + END_TOKEN.length(), begin));
              variable = base.substring(begin + START_TOKEN.length(), end);
              if (store.get(variable) != null)
              {
                  result.append(store.get(variable));
              }
              prec = end;
          }
          result.append(base.substring(prec + END_TOKEN.length(), base.length()));
  
          return result.toString();
      }
  
      /**
       * Test whether the string represent by value maps to a boolean
       * value or not. We will allow <code>true</code>, <code>on</code>,
       * and <code>yes</code> for a <code>true</code> boolean value, and
       * <code>false</code>, <code>off</code>, and <code>no</code> for
       * <code>false</code> boolean values.  Case of value to test for
       * boolean status is ignored.
       *
       * @param String The value to test for boolean state.
       * @return <code>true</code> or <code>false</code> if the supplied
       * text maps to a boolean value, or <code>null</code> otherwise.
       */
      public String testBoolean(String value)
      {
          String s = ((String)value).toLowerCase();
  
          if (s.equals("true") || s.equals("on") || s.equals("yes"))
          {
              return "true";
          }
          else if (s.equals("false") || s.equals("off") || s.equals("no"))
          {
              return "false";
          }
          else
          {
              return null;
          }
      }
  
      /**
       * Create an ExtendedProperties object that is a subset
       * of this one. Take into account duplicate keys
       * by using the setProperty() in ExtendedProperties.
       *
       * @param String prefix
       */
      public Configuration subset(String prefix)
      {
          PropertiesConfiguration c = new PropertiesConfiguration();
          Iterator keys = this.getKeys();
          boolean validSubset = false;
  
          while( keys.hasNext() )
          {
              Object key = keys.next();
  
              if( key instanceof String && ((String) key).startsWith(prefix) )
              {
                  if (!validSubset)
                  {
                      validSubset = true;
                  }
  
                  String newKey = null;
  
                  /*
                   * Check to make sure that c.subset(prefix) doesn't blow up when
                   * there is only a single property with the key prefix. This is
                   * not a useful subset but it is a valid subset.
                   */
                  if ( ((String)key).length() == prefix.length())
                  {
                      newKey = prefix;
                  }
                  else
                  {
                      newKey = ((String)key).substring(prefix.length() + 1);
                  }
  
                  /*
                   * use addPropertyDirect() - this will plug the data as is into
                   * the Map, but will also do the right thing re key accounting
                   */
                  c.addPropertyDirect(newKey, store.get(key));
              }
          }
  
          if (validSubset)
          {
              return (Configuration)  c;
          }
          else
          {
              return null;
          }
      }
  
      /**
       * check if the configuration is empty
       */
      public boolean isEmpty()
      {
          return store.isEmpty();
      }
  
      /**
       * check if the configuration contains the key
       */
      public boolean containsKey(String key)
      {
          return store.containsKey(key);
      }
  
      /**
       * Set a property, this will replace any previously
       * set values. Set values is implicitly a call
       * to clearProperty(key), addProperty(key,value).
       *
       * @param String key
       * @param String value
       */
      public void setProperty(String key, Object value)
      {
          clearProperty(key);
          addProperty(key,value);
      }
  
      /**
       * Clear a property in the configuration.
       *
       * @param String key to remove along with corresponding value.
       */
      public void clearProperty(String key)
      {
          if (containsKey(key))
          {
              /*
               * we also need to rebuild the keysAsListed or else things get
               * *very* confusing
               */
              for(int i = 0; i < keysAsListed.size(); i++)
              {
                  if ( ( (String) keysAsListed.get(i)).equals( key ) )
                  {
                      keysAsListed.remove(i);
                      break;
                  }
              }
              store.remove(key);
          }
      }
  
      /**
       * Get the list of the keys contained in the configuration
       * repository.
       *
       * @return An Iterator.
       */
      public Iterator getKeys()
      {
          return keysAsListed.iterator();
      }
  
      /**
       * Get a list of properties associated with the given
       * configuration key.
       *
       * @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.
       * @exception IllegalArgumentException if one of the tokens is
       * malformed (does not contain an equals sign).
       */
      public Properties getProperties(String key)
      {
          return getProperties(key, new Properties());
      }
  
      /**
       * Get a list of properties associated with the given
       * configuration key.
       *
       * @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.
       * @exception IllegalArgumentException if one of the tokens is
       * malformed (does not contain an equals sign).
       */
      public Properties getProperties(String key, Properties defaults)
      {
          /*
           * Grab an array of the tokens for this key.
           */
          String[] tokens = getStringArray(key);
  
          /*
           * Each token is of the form 'key=value'.
           */
          Properties props = new Properties(defaults);
          for (int i = 0; i < tokens.length; i++)
          {
              String token = tokens[i];
              int equalSign = token.indexOf('=');
              if (equalSign > 0)
              {
                  String pkey = token.substring(0, equalSign).trim();
                  String pvalue = token.substring(equalSign + 1).trim();
                  props.put(pkey, pvalue);
              }
              else
              {
                  throw new IllegalArgumentException('\'' + token +
                                                     "' does not contain " +
                                                     "an equals sign");
              }
          }
          return props;
      }
  
      /**
       * Get a boolean associated with the given configuration key.
       *
       * @param key The configuration key.
       * @return The associated boolean.
       * @exception NoSuchElementException is thrown if the key doesn't
       * map to an existing object.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Boolean.
       */
      public boolean getBoolean(String key)
      {
          Boolean b = getBoolean(key, (Boolean) null);
          if (b != null)
          {
              return b.booleanValue();
          }
          else
          {
              throw new NoSuchElementException(
                  '\'' + key + "' doesn't map to an existing object");
          }
      }
  
      /**
       * Get a boolean associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated boolean.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Boolean.
       */
      public boolean getBoolean(String key, boolean defaultValue)
      {
          return getBoolean(key, new Boolean(defaultValue)).booleanValue();
      }
  
      /**
       * Get a boolean associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated boolean if key is found and has valid
       * format, default value otherwise.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Boolean.
       */
      public Boolean getBoolean(String key, Boolean defaultValue)
      {
  
          Object value = store.get(key);
  
          if (value instanceof Boolean)
          {
              return (Boolean) value;
          }
          else if (value instanceof String)
          {
              String s = testBoolean((String)value);
              Boolean b = new Boolean(s);
              store.put(key, b);
              return b;
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return defaults.getBoolean(key, defaultValue);
              }
              else
              {
                  return defaultValue;
              }
          }
          else
          {
              throw new ClassCastException(
                  '\'' + key + "' doesn't map to a Boolean object");
          }
      }
  
      /**
       * Get a byte associated with the given configuration key.
       *
       * @param key The configuration key.
       * @return The associated byte.
       * @exception NoSuchElementException is thrown if the key doesn't
       * map to an existing object.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Byte.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public byte getByte(String key)
      {
          Byte b = getByte(key, null);
          if (b != null)
          {
              return b.byteValue();
          }
          else
          {
              throw new NoSuchElementException(
                  '\'' + key + " doesn't map to an existing object");
          }
      }
  
      /**
       * Get a byte associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated byte.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Byte.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public byte getByte(String key, byte defaultValue)
      {
          return getByte(key, new Byte(defaultValue)).byteValue();
      }
  
      /**
       * Get a byte associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated byte if key is found and has valid format, default
       *         value otherwise.
       * @exception ClassCastException is thrown if the key maps to an object that
       *            is not a Byte.
       * @exception NumberFormatException is thrown if the value mapped by the key
       *            has not a valid number format.
       */
      public Byte getByte(String key, Byte defaultValue)
      {
          Object value = store.get(key);
  
          if (value instanceof Byte)
          {
              return (Byte) value;
          }
          else if (value instanceof String)
          {
              Byte b = new Byte((String) value);
              store.put(key, b);
              return b;
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return defaults.getByte(key, defaultValue);
              }
              else
              {
                  return defaultValue;
              }
          }
          else
          {
              throw new ClassCastException(
                  '\'' + key + "' doesn't map to a Byte object");
          }
      }
  
      /**
       * Get a double associated with the given configuration key.
       *
       * @param key The configuration key.
       * @return The associated double.
       * @exception NoSuchElementException is thrown if the key doesn't
       * map to an existing object.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Double.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public double getDouble(String key)
      {
          Double d = getDouble(key, null);
          if (d != null)
          {
              return d.doubleValue();
          }
          else
          {
              throw new NoSuchElementException(
                  '\'' + key + "' doesn't map to an existing object");
          }
      }
  
      /**
       * Get a double associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated double.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Double.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public double getDouble(String key, double defaultValue)
      {
          return getDouble(key, new Double(defaultValue)).doubleValue();
      }
  
      /**
       * Get a double associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated double if key is found and has valid
       * format, default value otherwise.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Double.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public Double getDouble(String key, Double defaultValue)
      {
          Object value = store.get(key);
  
          if (value instanceof Double)
          {
              return (Double) value;
          }
          else if (value instanceof String)
          {
              Double d = new Double((String) value);
              store.put(key, d);
              return d;
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return defaults.getDouble(key, defaultValue);
              }
              else
              {
                  return defaultValue;
              }
          }
          else
          {
              throw new ClassCastException(
                  '\'' + key + "' doesn't map to a Double object");
          }
      }
  
      /**
       * Get a float associated with the given configuration key.
       *
       * @param key The configuration key.
       * @return The associated float.
       * @exception NoSuchElementException is thrown if the key doesn't
       * map to an existing object.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Float.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public float getFloat(String key)
      {
          Float f = getFloat(key, null);
          if (f != null)
          {
              return f.floatValue();
          }
          else
          {
              throw new NoSuchElementException(
                  '\'' + key + "' doesn't map to an existing object");
          }
      }
  
      /**
       * Get a float associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated float.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Float.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public float getFloat(String key, float defaultValue)
      {
          return getFloat(key, new Float(defaultValue)).floatValue();
      }
  
      /**
       * Get a float associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated float if key is found and has valid
       * format, default value otherwise.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Float.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public Float getFloat(String key, Float defaultValue)
      {
          Object value = store.get(key);
  
          if (value instanceof Float)
          {
              return (Float) value;
          }
          else if (value instanceof String)
          {
              Float f = new Float((String) value);
              store.put(key, f);
              return f;
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return defaults.getFloat(key, defaultValue);
              }
              else
              {
                  return defaultValue;
              }
          }
          else
          {
              throw new ClassCastException(
                  '\'' + key + "' doesn't map to a Float object");
          }
      }
  
      /**
       * Get a int associated with the given configuration key.
       *
       * @param key The configuration key.
       * @return The associated int.
       * @exception NoSuchElementException is thrown if the key doesn't
       * map to an existing object.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Integer.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public int getInt(String key)
      {
          Integer i = getInteger(key, null);
          if (i != null)
          {
              return i.intValue();
          }
          else
          {
              throw new NoSuchElementException(
                  '\'' + key + "' doesn't map to an existing object");
          }
      }
  
      /**
       * Get a int associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated int.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Integer.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public int getInt(String key, int defaultValue)
      {
          Integer i = getInteger(key, null);
  
          if (i == null)
          {
              return defaultValue;
          }
  
          return i.intValue();
      }
  
  
      /**
       * Get a int associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated int if key is found and has valid format, default
       *         value otherwise.
       * @exception ClassCastException is thrown if the key maps to an object that
       *         is not a Integer.
       * @exception NumberFormatException is thrown if the value mapped by the key
       *         has not a valid number format.
       */
      public Integer getInteger(String key, Integer defaultValue)
      {
          Object value = store.get(key);
  
          if (value instanceof Integer)
          {
              return (Integer) value;
          }
          else if (value instanceof String)
          {
              Integer i = new Integer((String) value);
              store.put(key, i);
              return i;
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return defaults.getInteger(key, defaultValue);
              }
              else
              {
                  return defaultValue;
              }
          }
          else
          {
              throw new ClassCastException(
                  '\'' + key + "' doesn't map to a Integer object");
          }
      }
  
      /**
       * Get a long associated with the given configuration key.
       *
       * @param key The configuration key.
       * @return The associated long.
       * @exception NoSuchElementException is thrown if the key doesn't
       * map to an existing object.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Long.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public long getLong(String key)
      {
          Long l = getLong(key, null);
          if (l != null)
          {
              return l.longValue();
          }
          else
          {
              throw new NoSuchElementException(
                  '\'' + key + "' doesn't map to an existing object");
          }
      }
  
      /**
       * Get a long associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated long.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Long.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public long getLong(String key, long defaultValue)
      {
          return getLong(key, new Long(defaultValue)).longValue();
      }
  
      /**
       * Get a long associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated long if key is found and has valid
       * format, default value otherwise.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Long.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public Long getLong(String key, Long defaultValue)
      {
          Object value = store.get(key);
  
          if (value instanceof Long)
          {
              return (Long) value;
          }
          else if (value instanceof String)
          {
              Long l = new Long((String) value);
              store.put(key, l);
              return l;
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return defaults.getLong(key, defaultValue);
              }
              else
              {
                  return defaultValue;
              }
          }
          else
          {
              throw new ClassCastException(
                  '\'' + key + "' doesn't map to a Long object");
          }
      }
  
      /**
       * Get a short associated with the given configuration key.
       *
       * @param key The configuration key.
       * @return The associated short.
       * @exception NoSuchElementException is thrown if the key doesn't
       * map to an existing object.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Short.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public short getShort(String key)
      {
          Short s = getShort(key, null);
          if (s != null)
          {
              return s.shortValue();
          }
          else
          {
              throw new NoSuchElementException(
                  '\'' + key + "' doesn't map to an existing object");
          }
      }
  
      /**
       * Get a short associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated short.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Short.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public short getShort(String key,
                            short defaultValue)
      {
          return getShort(key, new Short(defaultValue)).shortValue();
      }
  
      /**
       * Get a short associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated short if key is found and has valid
       * format, default value otherwise.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Short.
       * @exception NumberFormatException is thrown if the value mapped
       * by the key has not a valid number format.
       */
      public Short getShort(String key,
                            Short defaultValue)
      {
          Object value = store.get(key);
  
          if (value instanceof Short)
          {
              return (Short) value;
          }
          else if (value instanceof String)
          {
              Short s = new Short((String) value);
              store.put(key, s);
              return s;
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return defaults.getShort(key, defaultValue);
              }
              else
              {
                  return defaultValue;
              }
          }
          else
          {
              throw new ClassCastException(
                  '\'' + key + "' doesn't map to a Short object");
          }
      }
  
      /**
       * Get a string associated with the given configuration key.
       *
       * @param key The configuration key.
       * @return The associated string.
       * @exception ClassCastException is thrown if the key maps to an object that
       *            is not a String.
       */
      public String getString(String key)
      {
          return getString(key, null);
      }
  
      /**
       * Get a string associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated string if key is found, default value otherwise.
       * @exception ClassCastException is thrown if the key maps to an object that
       *            is not a String.
       */
      public String getString(String key, String defaultValue)
      {
          Object value = store.get(key);
  
          if (value instanceof String)
          {
              return (String) interpolate((String)value);
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return interpolate(defaults.getString(key, defaultValue));
              }
              else
              {
                  return interpolate(defaultValue);
              }
          }
          else if (value instanceof Vector)
          {
              return interpolate((String) ((Vector) value).get(0));
          }
          else
          {
              throw new ClassCastException(
                  '\'' + key + "' doesn't map to a String object");
          }
      }
  
      /**
       * Get an array of strings associated with the given configuration
       * key.
       *
       * @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.
       */
      public String[] getStringArray(String key)
      {
          Object value = store.get(key);
  
          // What's your vector, Victor?
          Vector vector;
          if (value instanceof String)
          {
              vector = new Vector(1);
              vector.addElement(value);
          }
          else if (value instanceof Vector)
          {
              vector = (Vector)value;
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return defaults.getStringArray(key);
              }
              else
              {
                  return new String[0];
              }
          }
          else
          {
              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;
      }
  
  
  
  
  
  
      /**
       * Get a Vector of strings associated with the given configuration key.
       *
       * @param key The configuration key.
       * @return The associated Vector.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Vector.
       */
      public Vector getVector(String key)
      {
          return getVector(key, null);
      }
  
      /**
       * Get a Vector of strings associated with the given configuration key.
       *
       * @param key The configuration key.
       * @param defaultValue The default value.
       * @return The associated Vector.
       * @exception ClassCastException is thrown if the key maps to an
       * object that is not a Vector.
       */
      public Vector getVector(String key, Vector defaultValue)
      {
          Object value = store.get(key);
  
          if (value instanceof Vector)
          {
              return (Vector) value;
          }
          else if (value instanceof String)
          {
              Vector v = new Vector(1);
              v.addElement((String) value);
              store.put(key, v);
              return v;
          }
          else if (value == null)
          {
              if (defaults != null)
              {
                  return defaults.getVector(key, defaultValue);
              }
              else
              {
                  return ((defaultValue == null) ?
                          new Vector() : defaultValue);
              }
          }
          else
          {
              throw new ClassCastException(
                  '\'' + key + "' doesn't map to a Vector object");
          }
      }
  
  
      /**
       * This class divides into tokens a property value.  Token
       * separator is "," but commas into the property value are escaped
       * using the backslash in front.
       */
      class PropertiesTokenizer extends StringTokenizer
      {
          /**
           * The property delimiter used while parsing (a comma).
           */
          static final String DELIMITER = ",";
  
          /**
           * Constructor.
           *
           * @param string A String.
           */
          public PropertiesTokenizer(String string)
          {
              super(string, DELIMITER);
          }
  
          /**
           * Check whether the object has more tokens.
           *
           * @return True if the object has more tokens.
           */
          public boolean hasMoreTokens()
          {
              return super.hasMoreTokens();
          }
  
          /**
           * Get next token.
           *
           * @return A String.
           */
          public String nextToken()
          {
              StringBuffer buffer = new StringBuffer();
  
              while (hasMoreTokens())
              {
                  String token = super.nextToken();
                  if (token.endsWith("\\"))
                  {
                      buffer.append(token.substring(0, token.length() - 1));
                      buffer.append(DELIMITER);
                  }
                  else
                  {
                      buffer.append(token);
                      break;
                  }
              }
  
              return buffer.toString().trim();
          }
      } // class PropertiesTokenizer
  
  }
  
  
  
  1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/package.html
  
  Index: package.html
  ===================================================================
  <html>
  <head>
  </head>
  
  <body>
  Configuration package.
  <p>
  <br>
  <font size="-2">$Id: package.html,v 1.1 2002/02/04 11:31:34 mpoeschl Exp $</font>
  </body>
  </html>
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-turbine-stratum/src/java/org/apache/stratum/configuration BaseConfiguration.java package.html Configuration.java PropertiesConfiguration.java XmlConfiguration.java AbstractConfiguration.java (2/2)

Posted by Daniel Rall <dl...@finemaltcoding.com>.
>       /**
>        * check if the configuration is empty
>        */
>       public boolean isEmpty()
>       {
>           return store.isEmpty();
>       }
>   
>       /**
>        * check if the configuration contains the key
>        */
>       public boolean containsKey(String key)
>       {
>           return store.containsKey(key);
>       }
>   
>       /**
>        * Set a property, this will replace any previously
>        * set values. Set values is implicitly a call
>        * to clearProperty(key), addProperty(key,value).
>        *
>        * @param String key
>        * @param String value
>        */
>       public void setProperty(String key, Object value)
>       {
>           clearProperty(key);
>           addProperty(key,value);
>       }
>   
>       /**
>        * Clear a property in the configuration.
>        *
>        * @param String key to remove along with corresponding value.
>        */
>       public void clearProperty(String key)
>       {
>           if (containsKey(key))
>           {
>               /*
>                * we also need to rebuild the keysAsListed or else things get
>                * *very* confusing
>                */
>               for(int i = 0; i < keysAsListed.size(); i++)
>               {
>                   if ( ( (String) keysAsListed.get(i)).equals( key ) )
>                   {
>                       keysAsListed.remove(i);
>                       break;
>                   }
>               }
>               store.remove(key);
>           }
>       }
>   
>       /**
>        * Get the list of the keys contained in the configuration
>        * repository.
>        *
>        * @return An Iterator.
>        */
>       public Iterator getKeys()
>       {
>           return keysAsListed.iterator();
>       }
>   
>       /**
>        * Get a list of properties associated with the given
>        * configuration key.
>        *
>        * @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.
>        * @exception IllegalArgumentException if one of the tokens is
>        * malformed (does not contain an equals sign).
>        */
>       public Properties getProperties(String key)
>       {
>           return getProperties(key, new Properties());
>       }
>   
>       /**
>        * Get a list of properties associated with the given
>        * configuration key.
>        *
>        * @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.
>        * @exception IllegalArgumentException if one of the tokens is
>        * malformed (does not contain an equals sign).
>        */
>       public Properties getProperties(String key, Properties defaults)
>       {
>           /*
>            * Grab an array of the tokens for this key.
>            */
>           String[] tokens = getStringArray(key);
>   
>           /*
>            * Each token is of the form 'key=value'.
>            */
>           Properties props = new Properties(defaults);
>           for (int i = 0; i < tokens.length; i++)
>           {
>               String token = tokens[i];
>               int equalSign = token.indexOf('=');
>               if (equalSign > 0)
>               {
>                   String pkey = token.substring(0, equalSign).trim();
>                   String pvalue = token.substring(equalSign + 1).trim();
>                   props.put(pkey, pvalue);
>               }
>               else
>               {
>                   throw new IllegalArgumentException('\'' + token +
>                                                      "' does not contain " +
>                                                      "an equals sign");
>               }
>           }
>           return props;
>       }
>   
>       /**
>        * Get a boolean associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @return The associated boolean.
>        * @exception NoSuchElementException is thrown if the key doesn't
>        * map to an existing object.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Boolean.
>        */
>       public boolean getBoolean(String key)
>       {
>           Boolean b = getBoolean(key, (Boolean) null);
>           if (b != null)
>           {
>               return b.booleanValue();
>           }
>           else
>           {
>               throw new NoSuchElementException(
>                   '\'' + key + "' doesn't map to an existing object");
>           }
>       }
>   
>       /**
>        * Get a boolean associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated boolean.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Boolean.
>        */
>       public boolean getBoolean(String key, boolean defaultValue)
>       {
>           return getBoolean(key, new Boolean(defaultValue)).booleanValue();
>       }
>   
>       /**
>        * Get a boolean associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated boolean if key is found and has valid
>        * format, default value otherwise.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Boolean.
>        */
>       public Boolean getBoolean(String key, Boolean defaultValue)
>       {
>   
>           Object value = store.get(key);
>   
>           if (value instanceof Boolean)
>           {
>               return (Boolean) value;
>           }
>           else if (value instanceof String)
>           {
>               String s = testBoolean((String)value);
>               Boolean b = new Boolean(s);
>               store.put(key, b);
>               return b;
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return defaults.getBoolean(key, defaultValue);
>               }
>               else
>               {
>                   return defaultValue;
>               }
>           }
>           else
>           {
>               throw new ClassCastException(
>                   '\'' + key + "' doesn't map to a Boolean object");
>           }
>       }
>   
>       /**
>        * Get a byte associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @return The associated byte.
>        * @exception NoSuchElementException is thrown if the key doesn't
>        * map to an existing object.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Byte.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public byte getByte(String key)
>       {
>           Byte b = getByte(key, null);
>           if (b != null)
>           {
>               return b.byteValue();
>           }
>           else
>           {
>               throw new NoSuchElementException(
>                   '\'' + key + " doesn't map to an existing object");
>           }
>       }
>   
>       /**
>        * Get a byte associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated byte.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Byte.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public byte getByte(String key, byte defaultValue)
>       {
>           return getByte(key, new Byte(defaultValue)).byteValue();
>       }
>   
>       /**
>        * Get a byte associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated byte if key is found and has valid format, default
>        *         value otherwise.
>        * @exception ClassCastException is thrown if the key maps to an object that
>        *            is not a Byte.
>        * @exception NumberFormatException is thrown if the value mapped by the key
>        *            has not a valid number format.
>        */
>       public Byte getByte(String key, Byte defaultValue)
>       {
>           Object value = store.get(key);
>   
>           if (value instanceof Byte)
>           {
>               return (Byte) value;
>           }
>           else if (value instanceof String)
>           {
>               Byte b = new Byte((String) value);
>               store.put(key, b);
>               return b;
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return defaults.getByte(key, defaultValue);
>               }
>               else
>               {
>                   return defaultValue;
>               }
>           }
>           else
>           {
>               throw new ClassCastException(
>                   '\'' + key + "' doesn't map to a Byte object");
>           }
>       }
>   
>       /**
>        * Get a double associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @return The associated double.
>        * @exception NoSuchElementException is thrown if the key doesn't
>        * map to an existing object.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Double.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public double getDouble(String key)
>       {
>           Double d = getDouble(key, null);
>           if (d != null)
>           {
>               return d.doubleValue();
>           }
>           else
>           {
>               throw new NoSuchElementException(
>                   '\'' + key + "' doesn't map to an existing object");
>           }
>       }
>   
>       /**
>        * Get a double associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated double.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Double.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public double getDouble(String key, double defaultValue)
>       {
>           return getDouble(key, new Double(defaultValue)).doubleValue();
>       }
>   
>       /**
>        * Get a double associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated double if key is found and has valid
>        * format, default value otherwise.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Double.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public Double getDouble(String key, Double defaultValue)
>       {
>           Object value = store.get(key);
>   
>           if (value instanceof Double)
>           {
>               return (Double) value;
>           }
>           else if (value instanceof String)
>           {
>               Double d = new Double((String) value);
>               store.put(key, d);
>               return d;
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return defaults.getDouble(key, defaultValue);
>               }
>               else
>               {
>                   return defaultValue;
>               }
>           }
>           else
>           {
>               throw new ClassCastException(
>                   '\'' + key + "' doesn't map to a Double object");
>           }
>       }
>   
>       /**
>        * Get a float associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @return The associated float.
>        * @exception NoSuchElementException is thrown if the key doesn't
>        * map to an existing object.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Float.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public float getFloat(String key)
>       {
>           Float f = getFloat(key, null);
>           if (f != null)
>           {
>               return f.floatValue();
>           }
>           else
>           {
>               throw new NoSuchElementException(
>                   '\'' + key + "' doesn't map to an existing object");
>           }
>       }
>   
>       /**
>        * Get a float associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated float.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Float.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public float getFloat(String key, float defaultValue)
>       {
>           return getFloat(key, new Float(defaultValue)).floatValue();
>       }
>   
>       /**
>        * Get a float associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated float if key is found and has valid
>        * format, default value otherwise.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Float.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public Float getFloat(String key, Float defaultValue)
>       {
>           Object value = store.get(key);
>   
>           if (value instanceof Float)
>           {
>               return (Float) value;
>           }
>           else if (value instanceof String)
>           {
>               Float f = new Float((String) value);
>               store.put(key, f);
>               return f;
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return defaults.getFloat(key, defaultValue);
>               }
>               else
>               {
>                   return defaultValue;
>               }
>           }
>           else
>           {
>               throw new ClassCastException(
>                   '\'' + key + "' doesn't map to a Float object");
>           }
>       }
>   
>       /**
>        * Get a int associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @return The associated int.
>        * @exception NoSuchElementException is thrown if the key doesn't
>        * map to an existing object.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Integer.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public int getInt(String key)
>       {
>           Integer i = getInteger(key, null);
>           if (i != null)
>           {
>               return i.intValue();
>           }
>           else
>           {
>               throw new NoSuchElementException(
>                   '\'' + key + "' doesn't map to an existing object");
>           }
>       }
>   
>       /**
>        * Get a int associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated int.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Integer.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public int getInt(String key, int defaultValue)
>       {
>           Integer i = getInteger(key, null);
>   
>           if (i == null)
>           {
>               return defaultValue;
>           }
>   
>           return i.intValue();
>       }
>   
>   
>       /**
>        * Get a int associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated int if key is found and has valid format, default
>        *         value otherwise.
>        * @exception ClassCastException is thrown if the key maps to an object that
>        *         is not a Integer.
>        * @exception NumberFormatException is thrown if the value mapped by the key
>        *         has not a valid number format.
>        */
>       public Integer getInteger(String key, Integer defaultValue)
>       {
>           Object value = store.get(key);
>   
>           if (value instanceof Integer)
>           {
>               return (Integer) value;
>           }
>           else if (value instanceof String)
>           {
>               Integer i = new Integer((String) value);
>               store.put(key, i);
>               return i;
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return defaults.getInteger(key, defaultValue);
>               }
>               else
>               {
>                   return defaultValue;
>               }
>           }
>           else
>           {
>               throw new ClassCastException(
>                   '\'' + key + "' doesn't map to a Integer object");
>           }
>       }
>   
>       /**
>        * Get a long associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @return The associated long.
>        * @exception NoSuchElementException is thrown if the key doesn't
>        * map to an existing object.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Long.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public long getLong(String key)
>       {
>           Long l = getLong(key, null);
>           if (l != null)
>           {
>               return l.longValue();
>           }
>           else
>           {
>               throw new NoSuchElementException(
>                   '\'' + key + "' doesn't map to an existing object");
>           }
>       }
>   
>       /**
>        * Get a long associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated long.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Long.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public long getLong(String key, long defaultValue)
>       {
>           return getLong(key, new Long(defaultValue)).longValue();
>       }
>   
>       /**
>        * Get a long associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated long if key is found and has valid
>        * format, default value otherwise.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Long.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public Long getLong(String key, Long defaultValue)
>       {
>           Object value = store.get(key);
>   
>           if (value instanceof Long)
>           {
>               return (Long) value;
>           }
>           else if (value instanceof String)
>           {
>               Long l = new Long((String) value);
>               store.put(key, l);
>               return l;
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return defaults.getLong(key, defaultValue);
>               }
>               else
>               {
>                   return defaultValue;
>               }
>           }
>           else
>           {
>               throw new ClassCastException(
>                   '\'' + key + "' doesn't map to a Long object");
>           }
>       }
>   
>       /**
>        * Get a short associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @return The associated short.
>        * @exception NoSuchElementException is thrown if the key doesn't
>        * map to an existing object.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Short.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public short getShort(String key)
>       {
>           Short s = getShort(key, null);
>           if (s != null)
>           {
>               return s.shortValue();
>           }
>           else
>           {
>               throw new NoSuchElementException(
>                   '\'' + key + "' doesn't map to an existing object");
>           }
>       }
>   
>       /**
>        * Get a short associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated short.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Short.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public short getShort(String key,
>                             short defaultValue)
>       {
>           return getShort(key, new Short(defaultValue)).shortValue();
>       }
>   
>       /**
>        * Get a short associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated short if key is found and has valid
>        * format, default value otherwise.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Short.
>        * @exception NumberFormatException is thrown if the value mapped
>        * by the key has not a valid number format.
>        */
>       public Short getShort(String key,
>                             Short defaultValue)
>       {
>           Object value = store.get(key);
>   
>           if (value instanceof Short)
>           {
>               return (Short) value;
>           }
>           else if (value instanceof String)
>           {
>               Short s = new Short((String) value);
>               store.put(key, s);
>               return s;
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return defaults.getShort(key, defaultValue);
>               }
>               else
>               {
>                   return defaultValue;
>               }
>           }
>           else
>           {
>               throw new ClassCastException(
>                   '\'' + key + "' doesn't map to a Short object");
>           }
>       }
>   
>       /**
>        * Get a string associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @return The associated string.
>        * @exception ClassCastException is thrown if the key maps to an object that
>        *            is not a String.
>        */
>       public String getString(String key)
>       {
>           return getString(key, null);
>       }
>   
>       /**
>        * Get a string associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated string if key is found, default value otherwise.
>        * @exception ClassCastException is thrown if the key maps to an object that
>        *            is not a String.
>        */
>       public String getString(String key, String defaultValue)
>       {
>           Object value = store.get(key);
>   
>           if (value instanceof String)
>           {
>               return (String) interpolate((String)value);
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return interpolate(defaults.getString(key, defaultValue));
>               }
>               else
>               {
>                   return interpolate(defaultValue);
>               }
>           }
>           else if (value instanceof Vector)
>           {
>               return interpolate((String) ((Vector) value).get(0));
>           }
>           else
>           {
>               throw new ClassCastException(
>                   '\'' + key + "' doesn't map to a String object");
>           }
>       }
>   
>       /**
>        * Get an array of strings associated with the given configuration
>        * key.
>        *
>        * @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.
>        */
>       public String[] getStringArray(String key)
>       {
>           Object value = store.get(key);
>   
>           // What's your vector, Victor?
>           Vector vector;
>           if (value instanceof String)
>           {
>               vector = new Vector(1);
>               vector.addElement(value);
>           }
>           else if (value instanceof Vector)
>           {
>               vector = (Vector)value;
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return defaults.getStringArray(key);
>               }
>               else
>               {
>                   return new String[0];
>               }
>           }
>           else
>           {
>               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;
>       }
>   
>   
>   
>   
>   
>   
>       /**
>        * Get a Vector of strings associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @return The associated Vector.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Vector.
>        */
>       public Vector getVector(String key)
>       {
>           return getVector(key, null);
>       }
>   
>       /**
>        * Get a Vector of strings associated with the given configuration key.
>        *
>        * @param key The configuration key.
>        * @param defaultValue The default value.
>        * @return The associated Vector.
>        * @exception ClassCastException is thrown if the key maps to an
>        * object that is not a Vector.
>        */
>       public Vector getVector(String key, Vector defaultValue)
>       {
>           Object value = store.get(key);
>   
>           if (value instanceof Vector)
>           {
>               return (Vector) value;
>           }
>           else if (value instanceof String)
>           {
>               Vector v = new Vector(1);
>               v.addElement((String) value);
>               store.put(key, v);
>               return v;
>           }
>           else if (value == null)
>           {
>               if (defaults != null)
>               {
>                   return defaults.getVector(key, defaultValue);
>               }
>               else
>               {
>                   return ((defaultValue == null) ?
>                           new Vector() : defaultValue);
>               }
>           }
>           else
>           {
>               throw new ClassCastException(
>                   '\'' + key + "' doesn't map to a Vector object");
>           }
>       }
>   
>   
>       /**
>        * This class divides into tokens a property value.  Token
>        * separator is "," but commas into the property value are escaped
>        * using the backslash in front.
>        */
>       class PropertiesTokenizer extends StringTokenizer
>       {
>           /**
>            * The property delimiter used while parsing (a comma).
>            */
>           static final String DELIMITER = ",";
>   
>           /**
>            * Constructor.
>            *
>            * @param string A String.
>            */
>           public PropertiesTokenizer(String string)
>           {
>               super(string, DELIMITER);
>           }
>   
>           /**
>            * Check whether the object has more tokens.
>            *
>            * @return True if the object has more tokens.
>            */
>           public boolean hasMoreTokens()
>           {
>               return super.hasMoreTokens();
>           }
>   
>           /**
>            * Get next token.
>            *
>            * @return A String.
>            */
>           public String nextToken()
>           {
>               StringBuffer buffer = new StringBuffer();
>   
>               while (hasMoreTokens())
>               {
>                   String token = super.nextToken();
>                   if (token.endsWith("\\"))
>                   {
>                       buffer.append(token.substring(0, token.length() - 1));
>                       buffer.append(DELIMITER);
>                   }
>                   else
>                   {
>                       buffer.append(token);
>                       break;
>                   }
>               }
>   
>               return buffer.toString().trim();
>           }
>       } // class PropertiesTokenizer
>   
>   }
>   
>   
>   
>   1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/package.html
>   
>   Index: package.html
>   ===================================================================
>   <html>
>   <head>
>   </head>
>   
>   <body>
>   Configuration package.
>   <p>
>   <br>
>   <font size="-2">$Id: package.html,v 1.1 2002/02/04 11:31:34 mpoeschl Exp $</font>
>   </body>
>   </html>
>   
>   
>   
>
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-turbine-stratum/src/java/org/apache/stratum/configuration BaseConfiguration.java package.html Configuration.java PropertiesConfiguration.java XmlConfiguration.java AbstractConfiguration.java (1/2)

Posted by Daniel Rall <dl...@finemaltcoding.com>.
What's the reasoning for not subclassing ExtendedProperties for the
default implementation?

mpoeschl@apache.org writes:

> mpoeschl    02/02/04 03:31:34
>
>   Modified:    src/java/org/apache/stratum/configuration Configuration.java
>                         PropertiesConfiguration.java XmlConfiguration.java
>   Added:       src/java/org/apache/stratum/configuration
>                         BaseConfiguration.java package.html
>   Removed:     src/java/org/apache/stratum/configuration
>                         AbstractConfiguration.java
>   Log:
>   new configuration package based on ExtendedProperties
>   
>   Revision  Changes    Path
>   1.2       +97 -19    jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/Configuration.java
>   
>   Index: Configuration.java
>   ===================================================================
>   RCS file: /home/cvs/jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/Configuration.java,v
>   retrieving revision 1.1
>   retrieving revision 1.2
>   diff -u -r1.1 -r1.2
>   --- Configuration.java	5 Jan 2002 03:22:59 -0000	1.1
>   +++ Configuration.java	4 Feb 2002 11:31:34 -0000	1.2
>   @@ -1,29 +1,107 @@
>    package org.apache.stratum.configuration;
>    
>   +/* ====================================================================
>   + * The Apache Software License, Version 1.1
>   + *
>   + * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
>   + * reserved.
>   + *
>   + * Redistribution and use in source and binary forms, with or without
>   + * modification, are permitted provided that the following conditions
>   + * are met:
>   + *
>   + * 1. Redistributions of source code must retain the above copyright
>   + *    notice, this list of conditions and the following disclaimer.
>   + *
>   + * 2. Redistributions in binary form must reproduce the above copyright
>   + *    notice, this list of conditions and the following disclaimer in
>   + *    the documentation and/or other materials provided with the
>   + *    distribution.
>   + *
>   + * 3. The end-user documentation included with the redistribution,
>   + *    if any, must include the following acknowledgment:
>   + *       "This product includes software developed by the
>   + *        Apache Software Foundation (http://www.apache.org/)."
>   + *    Alternately, this acknowledgment may appear in the software itself,
>   + *    if and wherever such third-party acknowledgments normally appear.
>   + *
>   + * 4. The names "Apache" and "Apache Software Foundation" and
>   + *    "Apache Turbine" must not be used to endorse or promote products
>   + *    derived from this software without prior written permission. For
>   + *    written permission, please contact apache@apache.org.
>   + *
>   + * 5. Products derived from this software may not be called "Apache",
>   + *    "Apache Turbine", nor may "Apache" appear in their name, without
>   + *    prior written permission of the Apache Software Foundation.
>   + *
>   + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
>   + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
>   + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
>   + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
>   + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>   + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>   + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
>   + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>   + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
>   + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
>   + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>   + * SUCH DAMAGE.
>   + * ====================================================================
>   + *
>   + * This software consists of voluntary contributions made by many
>   + * individuals on behalf of the Apache Software Foundation.  For more
>   + * information on the Apache Software Foundation, please see
>   + * <http://www.apache.org/>.
>   + */
>   +
>    import java.util.Iterator;
>   +import java.util.Properties;
>    import java.util.Vector;
>    
>   -// The general idea here is to make something that will work like
>   -// our extended properties and be compatible with the preferences
>   -// API if at all possible.
>   -
>   +/**
>   + * Configuration interface.
>   + * The general idea here is to make something that will work like our
>   + * extended properties and be compatible with the preferences API if at all
>   + * possible.
>   + *
>   + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
>   + * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
>   + * @version $Id: Configuration.java,v 1.2 2002/02/04 11:31:34 mpoeschl Exp $
>   + */
>    public interface Configuration
>   -{    
>   -    Vector getVector(String key);
>   -    String getString(String key);
>   +{
>   +    Configuration subset(String prefix);
>   +
>   +    boolean isEmpty();
>   +    boolean containsKey(String key);
>   +    void addProperty(String key, Object value);
>   +    void setProperty(String key, Object value);
>   +    void clearProperty(String key);
>        Iterator getKeys(String key);
>   -    int getInt(String key, int defaultValue);
>   -    
>   +    Iterator getKeys();
>   +    Properties getProperties();
>   +
>        // We probably want to at least try to be compatible with
>        // the new preferences API.
>   -    
>   -    // Iterator getKeys()
>   -    
>   -    // byte getByte(String key);
>   -    // short getShort(String key);
>   -    // long getLong(String key);
>   -    
>   -    // float getFloat(String key);
>   -    // boolean getBoolean(String key);
>   -    // double getDouble(String key);
>   +
>   +    boolean getBoolean(String key);
>   +    boolean getBoolean(String key, boolean defaultValue);
>   +//    Boolean getBoolean(String key, Boolean defaultValue);
>   +    byte getByte(String key);
>   +    double getDouble(String key);
>   +    float getFloat(String key);
>   +    int getInt(String key, int defaultValue);
>   +    Integer getInteger(String key, Integer defaultValue);
>   +    long getLong(String key);
>   +    long getLong(String key, long defaultValue);
>   +//    Long getLong(String key, Long defaultValue);
>   +    short getShort(String key);
>   +    String getString(String key);
>   +    String getString(String key, String defaultValue);
>   +    String[] getStringArray(String key);
>   +    Vector getVector(String key);
>   +    Vector getVector(String key, Vector defaultValue);
>   +
>   +
>   +
>    }
>   
>   
>   
>   1.2       +402 -3    jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/PropertiesConfiguration.java
>   
>   Index: PropertiesConfiguration.java
>   ===================================================================
>   RCS file: /home/cvs/jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/PropertiesConfiguration.java,v
>   retrieving revision 1.1
>   retrieving revision 1.2
>   diff -u -r1.1 -r1.2
>   --- PropertiesConfiguration.java	18 Jan 2002 22:26:05 -0000	1.1
>   +++ PropertiesConfiguration.java	4 Feb 2002 11:31:34 -0000	1.2
>   @@ -1,9 +1,408 @@
>    package org.apache.stratum.configuration;
>    
>   +/* ====================================================================
>   + * The Apache Software License, Version 1.1
>   + *
>   + * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
>   + * reserved.
>   + *
>   + * Redistribution and use in source and binary forms, with or without
>   + * modification, are permitted provided that the following conditions
>   + * are met:
>   + *
>   + * 1. Redistributions of source code must retain the above copyright
>   + *    notice, this list of conditions and the following disclaimer.
>   + *
>   + * 2. Redistributions in binary form must reproduce the above copyright
>   + *    notice, this list of conditions and the following disclaimer in
>   + *    the documentation and/or other materials provided with the
>   + *    distribution.
>   + *
>   + * 3. The end-user documentation included with the redistribution,
>   + *    if any, must include the following acknowledgment:
>   + *       "This product includes software developed by the
>   + *        Apache Software Foundation (http://www.apache.org/)."
>   + *    Alternately, this acknowledgment may appear in the software itself,
>   + *    if and wherever such third-party acknowledgments normally appear.
>   + *
>   + * 4. The names "Apache" and "Apache Software Foundation" and
>   + *    "Apache Turbine" must not be used to endorse or promote products
>   + *    derived from this software without prior written permission. For
>   + *    written permission, please contact apache@apache.org.
>   + *
>   + * 5. Products derived from this software may not be called "Apache",
>   + *    "Apache Turbine", nor may "Apache" appear in their name, without
>   + *    prior written permission of the Apache Software Foundation.
>   + *
>   + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
>   + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
>   + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
>   + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
>   + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>   + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>   + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
>   + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>   + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
>   + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
>   + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>   + * SUCH DAMAGE.
>   + * ====================================================================
>   + *
>   + * This software consists of voluntary contributions made by many
>   + * individuals on behalf of the Apache Software Foundation.  For more
>   + * information on the Apache Software Foundation, please see
>   + * <http://www.apache.org/>.
>   + */
>   +
>   +import java.io.File;
>   +import java.io.FileInputStream;
>   +import java.io.InputStream;
>   +import java.io.InputStreamReader;
>   +import java.io.IOException;
>   +import java.io.LineNumberReader;
>   +import java.io.Reader;
>   +import java.io.UnsupportedEncodingException;
>   +
>    // Borrow a lot of the code from ExtendedProperties, but leave
>    // the resource handling to the resources package.
>    
>   -public class PropertiesConfiguration
>   -    extends AbstractConfiguration
>   -{    
>   +/**
>   + * loads the configuration from a properties file. <p>
>   + *
>   + * <p>The Extended Properties syntax is explained here:
>   + *
>   + * <ul>
>   + *  <li>
>   + *   Each property has the syntax <code>key = value</code>
>   + *  </li>
>   + *  <li>
>   + *   The <i>key</i> may use any character but the equal sign '='.
>   + *  </li>
>   + *  <li>
>   + *   <i>value</i> may be separated on different lines if a backslash
>   + *   is placed at the end of the line that continues below.
>   + *  </li>
>   + *  <li>
>   + *   If <i>value</i> is a list of strings, each token is separated
>   + *   by a comma ','.
>   + *  </li>
>   + *  <li>
>   + *   Commas in each token are escaped placing a backslash right before
>   + *   the comma.
>   + *  </li>
>   + *  <li>
>   + *   If a <i>key</i> is used more than once, the values are appended
>   + *   like if they were on the same line separated with commas.
>   + *  </li>
>   + *  <li>
>   + *   Blank lines and lines starting with character '#' are skipped.
>   + *  </li>
>   + *  <li>
>   + *   If a property is named "include" (or whatever is defined by
>   + *   setInclude() and getInclude() and the value of that property is
>   + *   the full path to a file on disk, that file will be included into
>   + *   the ConfigurationsRepository. You can also pull in files relative
>   + *   to the parent configuration file. So if you have something
>   + *   like the following:
>   + *
>   + *   include = additional.properties
>   + *
>   + *   Then "additional.properties" is expected to be in the same
>   + *   directory as the parent configuration file.
>   + *
>   + *   Duplicate name values will be replaced, so be careful.
>   + *
>   + *  </li>
>   + * </ul>
>   + *
>   + * <p>Here is an example of a valid extended properties file:
>   + *
>   + * <p><pre>
>   + *      # lines starting with # are comments
>   + *
>   + *      # This is the simplest property
>   + *      key = value
>   + *
>   + *      # A long property may be separated on multiple lines
>   + *      longvalue = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
>   + *                  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
>   + *
>   + *      # This is a property with many tokens
>   + *      tokens_on_a_line = first token, second token
>   + *
>   + *      # This sequence generates exactly the same result
>   + *      tokens_on_multiple_lines = first token
>   + *      tokens_on_multiple_lines = second token
>   + *
>   + *      # commas may be escaped in tokens
>   + *      commas.excaped = Hi\, what'up?
>   + * </pre>
>   + *
>   + * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
>   + * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
>   + * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a>
>   + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
>   + * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
>   + * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
>   + * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
>   + * @author <a href="mailto:ipriha@surfeu.fi">Ilkka Priha</a>
>   + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
>   + * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
>   + * @version $Id: PropertiesConfiguration.java,v 1.2 2002/02/04 11:31:34 mpoeschl Exp $
>   + */
>   +public class PropertiesConfiguration extends BaseConfiguration
>   +{
>   +
>   +    /** File separator. */
>   +    protected String fileSeparator = System.getProperty("file.separator");
>   +
>   +    /**
>   +     * Base path of the configuration file used to create this Configuration
>   +     * object.
>   +     */
>   +    protected String basePath;
>   +
>   +    /**
>   +     * This is the name of the property that can point to other
>   +     * properties file for including other properties files.
>   +     */
>   +    protected static String include = "include";
>   +
>   +
>   +    /**
>   +     * Creates an empty Configuration
>   +     */
>   +    public PropertiesConfiguration()
>   +    {
>   +    }
>   +
>   +    /**
>   +     * Creates and loads the extended properties from the specified file.
>   +     *
>   +     * @param file A String.
>   +     * @exception IOException.
>   +     */
>   +    public PropertiesConfiguration(String file) throws IOException
>   +    {
>   +        this(file, null);
>   +    }
>   +
>   +    /**
>   +     * Creates and loads the extended properties from the specified file.
>   +     *
>   +     * @param file A String.
>   +     * @exception IOException.
>   +     */
>   +    public PropertiesConfiguration(String file, String defaultFile)
>   +        throws IOException
>   +    {
>   +//        this.file = file;
>   +
>   +        basePath = new File(file).getAbsolutePath();
>   +        basePath = basePath.substring(0, basePath.lastIndexOf(fileSeparator) + 1);
>   +
>   +        this.load(new FileInputStream(file));
>   +
>   +        if (defaultFile != null)
>   +        {
>   +            defaults = (BaseConfiguration)
>   +                    new PropertiesConfiguration(defaultFile);
>   +        }
>   +    }
>   +
>   +    /**
>   +     * Load the properties from the given input stream.
>   +     *
>   +     * @param input An InputStream.
>   +     * @exception IOException.
>   +     */
>   +    public void load(InputStream input) throws IOException
>   +    {
>   +        load(input, null);
>   +    }
>   +
>   +    /**
>   +     * Load the properties from the given input stream and using the specified
>   +     * encoding.
>   +     *
>   +     * @param input An InputStream.
>   +     * @param enc An encoding.
>   +     * @exception IOException.
>   +     */
>   +    public synchronized void load(InputStream input, String enc)
>   +            throws IOException
>   +    {
>   +        PropertiesReader reader = null;
>   +        if (enc != null)
>   +        {
>   +            try
>   +            {
>   +                reader =
>   +                    new PropertiesReader(new InputStreamReader(input, enc));
>   +            }
>   +            catch (UnsupportedEncodingException e)
>   +            {
>   +                // Get one with the default encoding...
>   +            }
>   +        }
>   +
>   +        if (reader == null)
>   +        {
>   +            reader =
>   +                new PropertiesReader(new InputStreamReader(input));
>   +        }
>   +
>   +        try
>   +        {
>   +            while (true)
>   +            {
>   +                String line = reader.readProperty();
>   +                int equalSign = line.indexOf('=');
>   +
>   +                if (equalSign > 0)
>   +                {
>   +                    String key = line.substring(0, equalSign).trim();
>   +                    String value = line.substring(equalSign + 1).trim();
>   +
>   +                    /*
>   +                     * Configure produces lines like this ... just
>   +                     * ignore them.
>   +                     */
>   +                    if ("".equals(value))
>   +                        continue;
>   +
>   +                    if (getInclude() != null &&
>   +                        key.equalsIgnoreCase(getInclude()))
>   +                    {
>   +                        /*
>   +                         * Recursively load properties files.
>   +                         */
>   +                        File file = null;
>   +
>   +                        if (value.startsWith(fileSeparator))
>   +                        {
>   +                            /*
>   +                             * We have an absolute path so we'll
>   +                             * use this.
>   +                             */
>   +                            file = new File(value);
>   +                        }
>   +                        else
>   +                        {
>   +                            /*
>   +                             * We have a relative path, and we have
>   +                             * two possible forms here. If we have the
>   +                             * "./" form then just strip that off first
>   +                             * before continuing.
>   +                             */
>   +                            if (value.startsWith("." + fileSeparator))
>   +                            {
>   +                                value = value.substring(2);
>   +                            }
>   +
>   +                            file = new File(basePath + value);
>   +                        }
>   +
>   +                        if (file != null && file.exists() && file.canRead())
>   +                        {
>   +                            load ( new FileInputStream(file));
>   +                        }
>   +                    }
>   +                    else
>   +                    {
>   +                        addProperty(key,value);
>   +                    }
>   +                }
>   +            }
>   +        }
>   +        catch (NullPointerException e)
>   +        {
>   +            /*
>   +             * Should happen only when EOF is reached.
>   +             */
>   +            return;
>   +        }
>   +    }
>   +
>   +    /**
>   +     * Gets the property value for including other properties files.
>   +     * By default it is "include".
>   +     *
>   +     * @return A String.
>   +     */
>   +    public String getInclude()
>   +    {
>   +        return this.include;
>   +    }
>   +
>   +    /**
>   +     * Sets the property value for including other properties files.
>   +     * By default it is "include".
>   +     *
>   +     * @param inc A String.
>   +     */
>   +    public void setInclude(String inc)
>   +    {
>   +        this.include = inc;
>   +    }
>   +
>   +
>   +    /**
>   +     * This class is used to read properties lines.  These lines do
>   +     * not terminate with new-line chars but rather when there is no
>   +     * backslash sign a the end of the line.  This is used to
>   +     * concatenate multiple lines for readability.
>   +     */
>   +    class PropertiesReader extends LineNumberReader
>   +    {
>   +        /**
>   +         * Constructor.
>   +         *
>   +         * @param reader A Reader.
>   +         */
>   +        public PropertiesReader(Reader reader)
>   +        {
>   +            super(reader);
>   +        }
>   +
>   +        /**
>   +         * Read a property.
>   +         *
>   +         * @return A String.
>   +         * @exception IOException.
>   +         */
>   +        public String readProperty() throws IOException
>   +        {
>   +            StringBuffer buffer = new StringBuffer();
>   +
>   +            try
>   +            {
>   +                while (true)
>   +                {
>   +                    String line = readLine().trim();
>   +                    if ((line.length() != 0) && (line.charAt(0) != '#'))
>   +                    {
>   +                        if (line.endsWith("\\"))
>   +                        {
>   +                            line = line.substring(0, line.length() - 1);
>   +                            buffer.append(line);
>   +                        }
>   +                        else
>   +                        {
>   +                            buffer.append(line);
>   +                            break;
>   +                        }
>   +                    }
>   +                }
>   +            }
>   +            catch (NullPointerException e)
>   +            {
>   +                return null;
>   +            }
>   +
>   +            return buffer.toString();
>   +        }
>   +    } // class PropertiesReader
>   +
>   +
>    }
>   
>   
>   
>   1.2       +3 -3      jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/XmlConfiguration.java
>   
>   Index: XmlConfiguration.java
>   ===================================================================
>   RCS file: /home/cvs/jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/XmlConfiguration.java,v
>   retrieving revision 1.1
>   retrieving revision 1.2
>   diff -u -r1.1 -r1.2
>   --- XmlConfiguration.java	18 Jan 2002 22:26:05 -0000	1.1
>   +++ XmlConfiguration.java	4 Feb 2002 11:31:34 -0000	1.2
>   @@ -1,5 +1,6 @@
>    package org.apache.stratum.configuration;
>    
>   +
>    /**
>     * <configuration>
>     *   <entries>
>   @@ -11,7 +12,6 @@
>     * </configuration>
>     *
>     */
>   -public class XmlConfiguration
>   -    extends AbstractConfiguration
>   -{    
>   +public class XmlConfiguration extends BaseConfiguration
>   +{
>    }
>   
>   
>   
>   1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/configuration/BaseConfiguration.java
>   
>   Index: BaseConfiguration.java
>   ===================================================================
>   package org.apache.stratum.configuration;
>   
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
>    * reserved.
>    *
>    * Redistribution and use in source and binary forms, with or without
>    * modification, are permitted provided that the following conditions
>    * are met:
>    *
>    * 1. Redistributions of source code must retain the above copyright
>    *    notice, this list of conditions and the following disclaimer.
>    *
>    * 2. Redistributions in binary form must reproduce the above copyright
>    *    notice, this list of conditions and the following disclaimer in
>    *    the documentation and/or other materials provided with the
>    *    distribution.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache Turbine" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache Turbine", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
>    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
>    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
>    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
>    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
>    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
>    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
>    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>    * SUCH DAMAGE.
>    * ====================================================================
>    *
>    * This software consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>   
>   import java.util.ArrayList;
>   import java.util.Hashtable;
>   import java.util.Iterator;
>   import java.util.NoSuchElementException;
>   import java.util.Properties;
>   import java.util.StringTokenizer;
>   import java.util.Vector;
>   
>   /**
>    * Basic configuration classe. Stores the configuration data but does not
>    * provide any load or save functions. If you want to load your Configuration
>    * from a file use PropertiesConfiguration or XmlConfiguration.
>    *
>    * This class extends normal Java properties by adding the possibility
>    * to use the same key many times concatenating the value strings
>    * instead of overwriting them.
>    *
>    * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
>    * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
>    * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a>
>    * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
>    * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
>    * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
>    * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
>    * @author <a href="mailto:ipriha@surfeu.fi">Ilkka Priha</a>
>    * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
>    * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
>    * @version $Id: BaseConfiguration.java,v 1.1 2002/02/04 11:31:34 mpoeschl Exp $
>    */
>   public class BaseConfiguration
>   {
>   
>       /* stores the configuration key-value pairs */
>       private Hashtable store = new Hashtable();
>   
>       /* stores the configuration key-value pairs */
>       protected BaseConfiguration defaults = null;
>   
>       /**
>        * These are the keys in the order they listed in the configuration file.
>        * This is useful when you wish to perform operations with configuration
>        * information in a particular order.
>        */
>       protected ArrayList keysAsListed = new ArrayList();
>   
>       protected final static String START_TOKEN = "${";
>       protected final static String END_TOKEN = "}";
>   
>       /**
>        * Add a property to the configuration. If it already exists then the value
>        * stated here will be added to the configuration entry. For example, if
>        *
>        * resource.loader = file
>        *
>        * is already present in the configuration and you
>        *
>        * addProperty("resource.loader", "classpath")
>        *
>        * Then you will end up with a Vector like the following:
>        *
>        * ["file", "classpath"]
>        *
>        * @param String key
>        * @param String value
>        */
>       public void addProperty(String key, Object 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);
>           }
>           else if (o instanceof Vector)
>           {
>               ((Vector) o).addElement(token);
>           }
>           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.
>                */
>               if (token instanceof String &&
>                   ((String)token).indexOf(PropertiesTokenizer.DELIMITER) > 0)
>               {
>                   PropertiesTokenizer tokenizer =
>                       new PropertiesTokenizer((String)token);
>   
>                   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);
>                   }
>               }
>               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);
>               }
>           }
>       }
>   
>       /**
>        * Adds a key/value pair to the map.  This routine does no magic morphing.
>        * It ensures the keylist is maintained
>        *
>        * @param key key to use for mapping
>        * @param obj object to store
>        */
>       protected void addPropertyDirect(String key, Object obj)
>       {
>           // safety check
>           if(! store.containsKey(key))
>           {
>               keysAsListed.add(key);
>           }
>   
>           // and the value
>           store.put(key, obj);
>       }
>   
>       /**
>        * 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)
>       {
>           if (base == null)
>           {
>               return null;
>           }
>   
>           int begin = -1;
>           int end = -1;
>           int prec = 0 - END_TOKEN.length();
>           String variable = null;
>           StringBuffer result = new StringBuffer();
>   
>           // FIXME: we should probably allow the escaping of the start token
>           while ( ((begin = base.indexOf(START_TOKEN, prec + END_TOKEN.length())) >-1)
>                   && ((end = base.indexOf(END_TOKEN, begin)) > -1) )
>           {
>               result.append(base.substring(prec + END_TOKEN.length(), begin));
>               variable = base.substring(begin + START_TOKEN.length(), end);
>               if (store.get(variable) != null)
>               {
>                   result.append(store.get(variable));
>               }
>               prec = end;
>           }
>           result.append(base.substring(prec + END_TOKEN.length(), base.length()));
>   
>           return result.toString();
>       }
>   
>       /**
>        * Test whether the string represent by value maps to a boolean
>        * value or not. We will allow <code>true</code>, <code>on</code>,
>        * and <code>yes</code> for a <code>true</code> boolean value, and
>        * <code>false</code>, <code>off</code>, and <code>no</code> for
>        * <code>false</code> boolean values.  Case of value to test for
>        * boolean status is ignored.
>        *
>        * @param String The value to test for boolean state.
>        * @return <code>true</code> or <code>false</code> if the supplied
>        * text maps to a boolean value, or <code>null</code> otherwise.
>        */
>       public String testBoolean(String value)
>       {
>           String s = ((String)value).toLowerCase();
>   
>           if (s.equals("true") || s.equals("on") || s.equals("yes"))
>           {
>               return "true";
>           }
>           else if (s.equals("false") || s.equals("off") || s.equals("no"))
>           {
>               return "false";
>           }
>           else
>           {
>               return null;
>           }
>       }
>   
>       /**
>        * Create an ExtendedProperties object that is a subset
>        * of this one. Take into account duplicate keys
>        * by using the setProperty() in ExtendedProperties.
>        *
>        * @param String prefix
>        */
>       public Configuration subset(String prefix)
>       {
>           PropertiesConfiguration c = new PropertiesConfiguration();
>           Iterator keys = this.getKeys();
>           boolean validSubset = false;
>   
>           while( keys.hasNext() )
>           {
>               Object key = keys.next();
>   
>               if( key instanceof String && ((String) key).startsWith(prefix) )
>               {
>                   if (!validSubset)
>                   {
>                       validSubset = true;
>                   }
>   
>                   String newKey = null;
>   
>                   /*
>                    * Check to make sure that c.subset(prefix) doesn't blow up when
>                    * there is only a single property with the key prefix. This is
>                    * not a useful subset but it is a valid subset.
>                    */
>                   if ( ((String)key).length() == prefix.length())
>                   {
>                       newKey = prefix;
>                   }
>                   else
>                   {
>                       newKey = ((String)key).substring(prefix.length() + 1);
>                   }
>   
>                   /*
>                    * use addPropertyDirect() - this will plug the data as is into
>                    * the Map, but will also do the right thing re key accounting
>                    */
>                   c.addPropertyDirect(newKey, store.get(key));
>               }
>           }
>   
>           if (validSubset)
>           {
>               return (Configuration)  c;
>           }
>           else
>           {
>               return null;
>           }
>       }
>   

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>