You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@turbine.apache.org by Daniel Rall <dl...@finemaltcoding.com> on 2002/02/06 18:49:04 UTC

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)

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>