⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abstractconfiguration.java

📁 java servlet著名论坛源代码
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
package net.myvietnam.mvncore.configuration;

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-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 acknowledgement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" 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"
 *    nor may "Apache" appear in their names 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.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Abstract configuration class. Provide basic functionality but does not
 * store any data. If you want to write your own Configuration class
 * then you should implement only abstract methods from this class.
 *
 * @author <a href="mailto:ksh@scand.com">Konstantin Shaposhnikov</a>
 * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
 * @version $Id: AbstractConfiguration.java,v 1.4 2004/06/01 13:25:39 skoehler Exp $
 */
public abstract class AbstractConfiguration implements Configuration
{
    /** how big the initial arraylist for splitting up name value pairs */
    private static final int INITIAL_LIST_SIZE = 2;

    private static Log log = LogFactory.getLog(AbstractConfiguration.class);
    /**
     * stores the configuration key-value pairs
     */
    protected Configuration defaults = null;

    /** start token */
    protected static final String START_TOKEN = "${";
    /** end token */
    protected static final String END_TOKEN = "}";

    /**
     * Empty constructor.
     */
    public AbstractConfiguration()
    {
    }

    /**
     * Creates an empty AbstractConfiguration object with
     * a Super-Object which is queries for every key.
     *
     * @param defaults Configuration defaults to use if key not in file
     */
    public AbstractConfiguration(Configuration defaults)
    {
        this();
        this.defaults = defaults;
    }

    /**
     * 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 key The Key to add the property to.
     * @param token The Value to add.
     */
    public void addProperty(String key, Object token)
    {
        if (token instanceof String)
        {
            for(Iterator it = processString((String) token).iterator();
            it.hasNext();)
            {
                addPropertyDirect(key, it.next());
            }
        }
        else if (token instanceof Collection)
        {
            for (Iterator it = ((Collection) token).iterator(); it.hasNext();)
            {
                addProperty(key, it.next());
            }
        }
        else
        {
            addPropertyDirect(key, token);
        }
    }

    /**
     * Read property. Should return <code>null</code> if the key doesn't
     * map to an existing object.
     *
     * @param key key to use for mapping
     *
     * @return object associated with the given configuration key.
     */
    protected abstract Object getPropertyDirect(String key);

    /**
     * Adds a key/value pair to the Configuration. Override this method to
     * provide write acces to underlying Configuration store.
     *
     * @param key key to use for mapping
     * @param obj object to store
     */
    protected abstract void addPropertyDirect(String key, Object obj);

    /**
     * interpolate key names to handle ${key} stuff
     *
     * @param base string to interpolate
     *
     * @return returns the key name with the ${key} substituted
     */
    protected String interpolate(String base)
    {
        return (interpolateHelper(base, null));
    }

    /**
     * Recursive handler for multple levels of interpolation.
     *
     * When called the first time, priorVariables should be null.
     *
     * @param base string with the ${key} variables
     * @param priorVariables serves two purposes: to allow checking for
     * loops, and creating a meaningful exception message should a loop
     * occur.  It's 0'th element will be set to the value of base from
     * the first call.  All subsequent interpolated variables are added
     * afterward.
     *
     * @return the string with the interpolation taken care of
     */
    protected String interpolateHelper(String base, List priorVariables)
    {
        if (base == null)
        {
            return null;
        }

        // on the first call initialize priorVariables
        // and add base as the first element
        if (priorVariables == null)
        {
            priorVariables = new ArrayList();
            priorVariables.add(base);
        }

        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 we've got a loop, create a useful exception message and throw
            if (priorVariables.contains(variable))
            {
                String initialBase = priorVariables.remove(0).toString();
                priorVariables.add(variable);
                StringBuffer priorVariableSb = new StringBuffer();

                // create a nice trace of interpolated variables like so:
                // var1->var2->var3
                for (Iterator it = priorVariables.iterator(); it.hasNext();)
                {
                    priorVariableSb.append(it.next());
                    if (it.hasNext())
                    {
                        priorVariableSb.append("->");
                    }
                }

                throw new IllegalStateException(
                    "infinite loop in property interpolation of "
                        + initialBase
                        + ": "
                        + priorVariableSb.toString());
            }
            // otherwise, add this variable to the interpolation list.
            else
            {
                priorVariables.add(variable);
            }

            //QUESTION: getProperty or getPropertyDirect
            Object value = getProperty(variable);
            if (value != null)
            {
                result.append(interpolateHelper(value.toString(),
                    priorVariables));

                // pop the interpolated variable off the stack
                // this maintains priorVariables correctness for
                // properties with multiple interpolations, e.g.
                // prop.name=${some.other.prop1}/blahblah/${some.other.prop2}
                priorVariables.remove(priorVariables.size() - 1);
            }
            else if (defaults != null && defaults.getString(variable,
                null) != null)
            {
                result.append(defaults.getString(variable));
            }
            else
            {
                //variable not defined - so put it back in the value
                result.append(START_TOKEN).append(variable).append(END_TOKEN);
            }
            prec = end;
        }
        result.append(base.substring(prec + END_TOKEN.length(), base.length()));

        return result.toString();
    }

    /**
     * Returns a Vector of Strings built from the supplied
     * String. Splits up CSV lists. If no commas are in the
     * String, simply returns a Vector with the String as its
     * first element
     *
     * @param token The String to tokenize
     *
     * @return A List of Strings
     */
    protected List processString(String token)
    {
        List retList = new ArrayList(INITIAL_LIST_SIZE);

        if (token.indexOf(PropertiesTokenizer.DELIMITER) > 0)
        {
            PropertiesTokenizer tokenizer =
                new PropertiesTokenizer(token);

            while (tokenizer.hasMoreTokens())
            {
                String value = tokenizer.nextToken();
                retList.add(value);
            }
        }
        else
        {
            retList.add(token);
        }

        //
        // We keep the sequence of the keys here and
        // we also keep it in the Container. So the
        // Keys are added to the store in the sequence that
        // is given in the properties
        return retList;
    }


    /**
     * 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 value 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.
     */
    protected final Boolean testBoolean(String value)
    {
        String s = value.toLowerCase();

        if (s.equals("true") || s.equals("on") || s.equals("yes"))
        {
            return Boolean.TRUE;
        }
        else if (s.equals("false") || s.equals("off") || s.equals("no"))
        {
            return Boolean.FALSE;
        }
        else
        {
            return null;
        }
    }

    /**
     * Create an BaseConfiguration object that is a subset
     * of this one.
     *
     * @param prefix prefix string for keys
     *
     * @return subset of configuration if there is keys, that match
     * given prefix, or <code>null</code> if there is no such keys.
     */
    public Configuration subset(String prefix)
    {
        BaseConfiguration c = new BaseConfiguration();
        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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -