Author: oheger
Date: Tue Dec 26 08:19:07 2006
New Revision: 490321

URL: http://svn.apache.org/viewvc?view=rev&rev=490321
Log:
CONFIGURATION-192: Incorporated lang's StrSubstitutor for variable 
interpolation; interpolation has been made more customizable

Added:
    
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/interpol/
    
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/interpol/ConfigurationInterpolator.java
   (with props)
    
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/interpol/
    
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/interpol/TestConfigurationInterpolator.java
   (with props)
Modified:
    
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java
    
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java
    
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestBaseConfiguration.java

Modified: 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java?view=diff&rev=490321&r1=490320&r2=490321
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java
 (original)
+++ 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java
 Tue Dec 26 08:19:07 2006
@@ -28,7 +28,10 @@
 import org.apache.commons.collections.Predicate;
 import org.apache.commons.collections.iterators.FilterIterator;
 import org.apache.commons.configuration.event.EventSource;
+import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
 import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.text.StrLookup;
+import org.apache.commons.lang.text.StrSubstitutor;
 
 /**
  * <p>Abstract configuration class. Provides basic functionality but does not
@@ -107,6 +110,9 @@
      */
     private boolean throwExceptionOnMissing;
 
+    /** Stores a reference to the object that handles variable interpolation.*/
+    private StrSubstitutor substitutor;
+
     /**
      * For configurations extending AbstractConfiguration, allow them to change
      * the listDelimiter from the default comma (","). This value will be used
@@ -228,6 +234,45 @@
     public boolean isThrowExceptionOnMissing()
     {
         return throwExceptionOnMissing;
+    }
+
+    /**
+     * Returns the object that is responsible for variable interpolation.
+     *
+     * @return the object responsible for variable interpolation
+     * @since 1.4
+     */
+    public synchronized StrSubstitutor getSubstitutor()
+    {
+        if (substitutor == null)
+        {
+            substitutor = new StrSubstitutor(createInterpolator());
+        }
+        return substitutor;
+    }
+
+    /**
+     * Creates the interpolator object that is responsible for variable
+     * interpolation. This method is invoked on first access of the
+     * interpolation features. It creates a new instance of
+     * <code>ConfigurationInterpolator</code> and sets the default lookup
+     * object to an implementation that queries this configuration.
+     *
+     * @return the newly created interpolator object
+     * @since 1.4
+     */
+    protected ConfigurationInterpolator createInterpolator()
+    {
+        ConfigurationInterpolator interpol = new ConfigurationInterpolator();
+        interpol.setDefaultLookup(new StrLookup()
+        {
+            public String lookup(String var)
+            {
+                Object prop = resolveContainerStore(var);
+                return (prop != null) ? prop.toString() : null;
+            }
+        });
+        return interpol;
     }
 
     /**

Modified: 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java?view=diff&rev=490321&r1=490320&r2=490321
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java
 (original)
+++ 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java
 Tue Dec 26 08:19:07 2006
@@ -681,111 +681,11 @@
     {
         if (value instanceof String)
         {
-            return interpolateHelper((String) value, null, config);
+            return config.getSubstitutor().replace((String) value);
         }
         else
         {
             return value;
         }
-    }
-
-    /**
-     * Recursive handler for multple levels of interpolation. This will be
-     * replaced when Commons Lang provides an interpolation feature. 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.
-     * @param config the current configuration
-     * @return the string with the interpolation taken care of
-     */
-    private static String interpolateHelper(String base, List priorVariables,
-            AbstractConfiguration config)
-    {
-        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 - AbstractConfiguration.END_TOKEN.length();
-        StringBuffer result = new StringBuffer();
-
-        // FIXME: we should probably allow the escaping of the start token
-        while (((begin = base.indexOf(AbstractConfiguration.START_TOKEN, prec
-                + AbstractConfiguration.END_TOKEN.length())) > -1)
-                && ((end = base.indexOf(AbstractConfiguration.END_TOKEN, 
begin)) > -1))
-        {
-            result.append(base.substring(prec
-                    + AbstractConfiguration.END_TOKEN.length(), begin));
-            String variable = base.substring(begin
-                    + AbstractConfiguration.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);
-            }
-
-            Object value = config.resolveContainerStore(variable);
-            if (value != null)
-            {
-                result.append(interpolateHelper(value.toString(),
-                        priorVariables, config));
-
-                // 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
-            {
-                // variable not defined - so put it back in the value
-                result.append(AbstractConfiguration.START_TOKEN);
-                result.append(variable);
-                result.append(AbstractConfiguration.END_TOKEN);
-            }
-
-            prec = end;
-        }
-        result.append(base.substring(prec
-                + AbstractConfiguration.END_TOKEN.length(), base.length()));
-        return result.toString();
     }
 }

Added: 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/interpol/ConfigurationInterpolator.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/interpol/ConfigurationInterpolator.java?view=auto&rev=490321
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/interpol/ConfigurationInterpolator.java
 (added)
+++ 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/interpol/ConfigurationInterpolator.java
 Tue Dec 26 08:19:07 2006
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.configuration.interpol;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.text.StrLookup;
+
+/**
+ * <p>
+ * A class that handles interpolation (variable substitution) for configuration
+ * objects.
+ * </p>
+ * <p>
+ * Each instance of <code>AbstractConfiguration</code> is associated with an
+ * object of this class. Each interpolation tasks are delegated to this object.
+ * </p>
+ * <p>
+ * <code>ConfigurationInterpolator</code> works together with the
+ * <code>StrSubstitutor</code> class from <a
+ * href="http://jakarta.apache.org/commons/lang";>Commons Lang</a>. By extending
+ * <code>StrLookup</code> it is able to provide values for variables that
+ * appear in expressions.
+ * </p>
+ * <p>
+ * The basic idea of this class is that it can maintain a set of primitive
+ * <code>StrLookup</code> objects, each of which are identified by a special
+ * prefix. The variables to be processed have the form
+ * <code>${prefix:name}</code>. <code>ConfigurationInterpolator</code> will
+ * extract the prefix and determine, which primitive lookup object is 
registered
+ * for it. Then the name of the variable is passed to this object to obtain the
+ * actual value. It is also possible to define a default lookup object, which
+ * will be used for variables that do not have a prefix.
+ * </p>
+ * <p>
+ * When a new instance of this class is created it is initialized with a 
default
+ * set of primitive lookup objects. This set can be customized using the static
+ * methods <code>registerGlobalLookup()</code> and
+ * <code>deregisterGlobalLookup()</code>. Per default it contains the
+ * following standard lookup objects:
+ * </p>
+ * <p>
+ * <table border="1">
+ * <tr>
+ * <th>Prefix</th>
+ * <th>Lookup object</th>
+ * </tr>
+ * <tr>
+ * <td valign="top">sys</td>
+ * <td>With this prefix a lookup object is associated that is able to resolve
+ * system properties.</td>
+ * </tr>
+ * </table>
+ * </p>
+ * <p>
+ * After an instance has been created the current set of lookup objects can be
+ * modified using the <code>registerLookup()</code> and
+ * <code>deregisterLookup()</code> methods. The default lookup object (that is
+ * invoked for variables without a prefix) can be set with the
+ * <code>setDefaultLookup()</code> method. (If a
+ * <code>ConfigurationInterpolator</code> instance is created by a
+ * configuration object, this lookup points to the configuration itself, so 
that
+ * variables are resolved using the configuration's properties. This ensures
+ * backward compatibility to earlier version of Commons Configuration.)
+ * </p>
+ * <p>
+ * Implementation node: Instances of this class are not thread-safe related to
+ * modifications of their current set of registered lookup objects. It is
+ * intended that each instance is associated with a single
+ * <code>Configuration</conde>
+ * object and used for its interpolation tasks.</p>
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ * @since 1.4
+ * @author <a
+ * 
href="http://jakarta.apache.org/commons/configuration/team-list.html";>Commons
+ * Configuration team</a>
+ */
+public class ConfigurationInterpolator extends StrLookup
+{
+    /**
+     * Constant for the prefix of the standard lookup object for resolving
+     * system properties.
+     */
+    public static final String PREFIX_SYSPROPERTIES = "sys";
+
+    /** Constant for the prefix separator. */
+    private static final char PREFIX_SEPARATOR = ':';
+
+    /** A map with the globally registered lookup objects. */
+    private static Map globalLookups;
+
+    /** A map with the locally registered lookup objects. */
+    private Map localLookups;
+
+    /** Stores the default lookup object. */
+    private StrLookup defaultLookup;
+
+    /**
+     * Creates a new instance of <code>ConfigurationInterpolator</code>.
+     */
+    public ConfigurationInterpolator()
+    {
+        synchronized (globalLookups)
+        {
+            localLookups = new HashMap(globalLookups);
+        }
+    }
+
+    /**
+     * Registers the given lookup object for the specified prefix globally. 
This
+     * means that all instances that are created later will use this lookup
+     * object for this prefix. If for this prefix a lookup object is already
+     * registered, the new lookup object will replace the old one. Note that 
the
+     * lookup objects registered here will be shared between multiple clients.
+     * So they should be thread-safe.
+     *
+     * @param prefix the variable prefix (must not be <b>null</b>)
+     * @param lookup the lookup object to be used for this prefix (must not be
+     * <b>null</b>)
+     */
+    public static void registerGlobalLookup(String prefix, StrLookup lookup)
+    {
+        if (prefix == null)
+        {
+            throw new IllegalArgumentException(
+                    "Prefix for lookup object must not be null!");
+        }
+        if (lookup == null)
+        {
+            throw new IllegalArgumentException(
+                    "Lookup object must not be null!");
+        }
+        synchronized (globalLookups)
+        {
+            globalLookups.put(prefix, lookup);
+        }
+    }
+
+    /**
+     * Deregisters the global lookup object for the specified prefix. This 
means
+     * that this lookup object won't be available for later created instances
+     * any more. For already existing instances this operation does not have 
any
+     * impact.
+     *
+     * @param prefix the variable prefix
+     * @return a flag whether for this prefix a lookup object had been
+     * registered
+     */
+    public static boolean deregisterGlobalLookup(String prefix)
+    {
+        synchronized (globalLookups)
+        {
+            return globalLookups.remove(prefix) != null;
+        }
+    }
+
+    /**
+     * Registers the given lookup object for the specified prefix at this
+     * instance. From now on this lookup object will be used for variables that
+     * have the specified prefix.
+     *
+     * @param prefix the variable prefix (must not be <b>null</b>)
+     * @param lookup the lookup object to be used for this prefix (must not be
+     * <b>null</b>)
+     */
+    public void registerLookup(String prefix, StrLookup lookup)
+    {
+        if (prefix == null)
+        {
+            throw new IllegalArgumentException(
+                    "Prefix for lookup object must not be null!");
+        }
+        if (lookup == null)
+        {
+            throw new IllegalArgumentException(
+                    "Lookup object must not be null!");
+        }
+        localLookups.put(prefix, lookup);
+    }
+
+    /**
+     * Deregisters the lookup object for the specified prefix at this instance.
+     * It will be removed from this instance.
+     *
+     * @param prefix the variable prefix
+     * @return a flag whether for this prefix a lookup object had been
+     * registered
+     */
+    public boolean deregisterLookup(String prefix)
+    {
+        return localLookups.remove(prefix) != null;
+    }
+
+    /**
+     * Returns a set with the prefixes, for which lookup objects are registered
+     * at this instance. This means that variables with these prefixes can be
+     * processed.
+     *
+     * @return a set with the registered variable prefixes
+     */
+    public Set prefixSet()
+    {
+        return localLookups.keySet();
+    }
+
+    /**
+     * Returns the default lookup object.
+     *
+     * @return the default lookup object
+     */
+    public StrLookup getDefaultLookup()
+    {
+        return defaultLookup;
+    }
+
+    /**
+     * Sets the default lookup object. This lookup object will be used for all
+     * variables without a special prefix. If it is set to <b>null</b>, such
+     * variables won't be processed.
+     *
+     * @param defaultLookup the new default lookup object
+     */
+    public void setDefaultLookup(StrLookup defaultLookup)
+    {
+        this.defaultLookup = defaultLookup;
+    }
+
+    /**
+     * Resolves the specified variable. This implementation will try to extract
+     * a variable prefix from the given variable name (the first colon (':') is
+     * used as prefix separator). It then passes the name of the variable with
+     * the prefix stripped to the lookup object registered for this prefix. If
+     * no prefix can be found, the default lookup object will be used.
+     *
+     * @param var the name of the variable whose value is to be looked up
+     * @return the value of this variable or <b>null</b> if it cannot be
+     * resolved
+     */
+    public String lookup(String var)
+    {
+        if (var == null)
+        {
+            return null;
+        }
+
+        int prefixPos = var.indexOf(PREFIX_SEPARATOR);
+        if (prefixPos < 0)
+        {
+            return fetchNoPrefixLookup().lookup(var);
+        }
+        else
+        {
+            String prefix = var.substring(0, prefixPos);
+            String name = var.substring(prefixPos + 1);
+            return fetchLookupForPrefix(prefix).lookup(name);
+        }
+    }
+
+    /**
+     * Returns the lookup object to be used for variables without a prefix. 
This
+     * implementation will check whether a default lookup object was set. If
+     * this is the case, it will be returned. Otherwise a <b>null</b> lookup
+     * object will be returned.
+     *
+     * @return the lookup object to be used for variables without a prefix
+     */
+    protected StrLookup fetchNoPrefixLookup()
+    {
+        return (getDefaultLookup() != null) ? getDefaultLookup() : StrLookup
+                .noneLookup();
+    }
+
+    /**
+     * Obtains the lookup object for the specified prefix. This method is 
called
+     * by the <code>lookup()</code> method. This implementation will check
+     * whether a lookup object is registered for the given prefix. If not, a
+     * <b>null</b> lookup object will be returned.
+     *
+     * @param prefix the prefix
+     * @return the lookup object to be used for this prefix
+     */
+    protected StrLookup fetchLookupForPrefix(String prefix)
+    {
+        StrLookup lookup = (StrLookup) localLookups.get(prefix);
+        if (lookup == null)
+        {
+            lookup = StrLookup.noneLookup();
+        }
+        return lookup;
+    }
+
+    // static initializer, sets up the map with the standard lookups
+    static
+    {
+        globalLookups = new HashMap();
+        globalLookups.put(PREFIX_SYSPROPERTIES, StrLookup
+                .systemPropertiesLookup());
+    }
+}

Propchange: 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/interpol/ConfigurationInterpolator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/interpol/ConfigurationInterpolator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/interpol/ConfigurationInterpolator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestBaseConfiguration.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestBaseConfiguration.java?view=diff&rev=490321&r1=490320&r2=490321
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestBaseConfiguration.java
 (original)
+++ 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestBaseConfiguration.java
 Tue Dec 26 08:19:07 2006
@@ -674,6 +674,48 @@
         assertEquals("Wrong int property", 42, subset.getInt("b"));
     }
 
+    /**
+     * Tests interpolation when the referred property is not found.
+     */
+    public void testInterpolationUnknownProperty()
+    {
+        config.addProperty("test.interpol", "${unknown.property}");
+        assertEquals("Wrong interpolated unknown property",
+                "${unknown.property}", config.getString("test.interpol"));
+    }
+
+    /**
+     * Tests interpolation of system properties.
+     */
+    public void testInterpolationSystemProperties()
+    {
+        String[] sysProperties =
+        { "java.version", "java.vendor", "os.name", "java.class.path" };
+        for (int i = 0; i < sysProperties.length; i++)
+        {
+            config.addProperty("prop" + i, "${sys:" + sysProperties[i] + "}");
+        }
+
+        for (int i = 0; i < sysProperties.length; i++)
+        {
+            assertEquals("Wrong value for system property " + sysProperties[i],
+                    System.getProperty(sysProperties[i]), config
+                            .getString("prop" + i));
+        }
+    }
+
+    /**
+     * Tests whether a variable can be escaped, so that it won't be
+     * interpolated.
+     */
+    public void testInterpolationEscaped()
+    {
+        config.addProperty("var", "x");
+        config.addProperty("escVar", "Use the variable $${${var}}.");
+        assertEquals("Wrong escaped variable", "Use the variable ${x}.", config
+                .getString("escVar"));
+    }
+
     public void testGetHexadecimalValue()
     {
         config.setProperty("number", "0xFF");

Added: 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/interpol/TestConfigurationInterpolator.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/interpol/TestConfigurationInterpolator.java?view=auto&rev=490321
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/interpol/TestConfigurationInterpolator.java
 (added)
+++ 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/interpol/TestConfigurationInterpolator.java
 Tue Dec 26 08:19:07 2006
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.configuration.interpol;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.lang.text.StrLookup;
+
+import junit.framework.TestCase;
+
+/**
+ * Test class for ConfigurationInterpolator.
+ *
+ * @version $Id$
+ */
+public class TestConfigurationInterpolator extends TestCase
+{
+    /** Constant for a test variable prefix. */
+    private static final String TEST_PREFIX = "prefix";
+
+    /** Constant for a test variable name. */
+    private static final String TEST_NAME = "varname";
+
+    /** Constant for the value of the test variable. */
+    private static final String TEST_VALUE = "TestVariableValue";
+
+    /** Stores the object to be tested. */
+    private ConfigurationInterpolator interpolator;
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        interpolator = new ConfigurationInterpolator();
+    }
+
+    /**
+     * Cleans the test environment. Deregisters the test lookup object if
+     * necessary.
+     */
+    protected void tearDown() throws Exception
+    {
+        ConfigurationInterpolator.deregisterGlobalLookup(TEST_PREFIX);
+    }
+
+    /**
+     * Tests creating an instance. Does it contain some predefined lookups?
+     */
+    public void testInit()
+    {
+        assertNull("A default lookup is set", interpolator.getDefaultLookup());
+        assertFalse("No predefined lookups", 
interpolator.prefixSet().isEmpty());
+    }
+
+    /**
+     * Tries to register a global lookup for a null prefix. This should cause 
an
+     * exception.
+     */
+    public void testRegisterGlobalLookupNullPrefix()
+    {
+        try
+        {
+            ConfigurationInterpolator.registerGlobalLookup(null, StrLookup
+                    .noneLookup());
+            fail("Could register global lookup with null prefix!");
+        }
+        catch (IllegalArgumentException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tries to register a global null lookup. This should cause an exception.
+     */
+    public void testRegisterGlobalLookupNull()
+    {
+        try
+        {
+            ConfigurationInterpolator.registerGlobalLookup(TEST_PREFIX, null);
+            fail("Could register global null lookup!");
+        }
+        catch (IllegalArgumentException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests registering a global lookup object. This lookup object should then
+     * be available for instances created later on.
+     */
+    public void testRegisterGlobalLookup()
+    {
+        ConfigurationInterpolator.registerGlobalLookup(TEST_PREFIX, StrLookup
+                .noneLookup());
+        ConfigurationInterpolator int2 = new ConfigurationInterpolator();
+        assertTrue("No lookup registered for test prefix", int2.prefixSet()
+                .contains(TEST_PREFIX));
+        assertFalse("Existing instance was modified", interpolator.prefixSet()
+                .contains(TEST_PREFIX));
+    }
+
+    /**
+     * Tests deregistering a global lookup object.
+     */
+    public void testDeregisterGlobalLookup()
+    {
+        ConfigurationInterpolator.registerGlobalLookup(TEST_PREFIX, StrLookup
+                .noneLookup());
+        assertTrue("Lookup could not be deregistered",
+                ConfigurationInterpolator.deregisterGlobalLookup(TEST_PREFIX));
+        ConfigurationInterpolator int2 = new ConfigurationInterpolator();
+        assertFalse("Deregistered lookup still available", int2.prefixSet()
+                .contains(TEST_PREFIX));
+    }
+
+    /**
+     * Tests deregistering an unknown lookup.
+     */
+    public void testDeregisterGlobalLookupNonExisting()
+    {
+        assertFalse("Could deregister unknown global lookup",
+                ConfigurationInterpolator.deregisterGlobalLookup(TEST_PREFIX));
+    }
+
+    /**
+     * Tests registering a lookup object at an instance.
+     */
+    public void testRegisterLookup()
+    {
+        int cnt = interpolator.prefixSet().size();
+        interpolator.registerLookup(TEST_PREFIX, StrLookup.noneLookup());
+        assertTrue("New lookup not registered", interpolator.prefixSet()
+                .contains(TEST_PREFIX));
+        assertEquals("Wrong number of registered lookups", cnt + 1,
+                interpolator.prefixSet().size());
+        ConfigurationInterpolator int2 = new ConfigurationInterpolator();
+        assertFalse("Local registration has global impact", int2.prefixSet()
+                .contains(TEST_PREFIX));
+    }
+
+    /**
+     * Tests registering a null lookup object. This should cause an exception.
+     */
+    public void testRegisterLookupNull()
+    {
+        try
+        {
+            interpolator.registerLookup(TEST_PREFIX, null);
+            fail("Could register null lookup!");
+        }
+        catch (IllegalArgumentException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests registering a lookup object for an undefined prefix. This should
+     * cause an exception.
+     */
+    public void testRegisterLookupNullPrefix()
+    {
+        try
+        {
+            interpolator.registerLookup(null, StrLookup.noneLookup());
+            fail("Could register lookup for null prefix!");
+        }
+        catch (IllegalArgumentException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests deregistering a local lookup object.
+     */
+    public void testDeregisterLookup()
+    {
+        interpolator.registerLookup(TEST_PREFIX, StrLookup.noneLookup());
+        assertTrue("Derigstration not successfull", interpolator
+                .deregisterLookup(TEST_PREFIX));
+        assertFalse("Deregistered prefix still contained", interpolator
+                .prefixSet().contains(TEST_PREFIX));
+    }
+
+    /**
+     * Tests deregistering an unknown lookup object.
+     */
+    public void testDeregisterLookupNonExisting()
+    {
+        assertFalse("Could deregister unknown lookup", interpolator
+                .deregisterLookup(TEST_PREFIX));
+    }
+
+    /**
+     * Tests whether a variable can be resolved using the associated lookup
+     * object. The lookup is identified by the variable's prefix.
+     */
+    public void testLookupWithPrefix()
+    {
+        interpolator.registerLookup(TEST_PREFIX, setUpTestLookup());
+        assertEquals("Wrong variable value", TEST_VALUE, interpolator
+                .lookup(TEST_PREFIX + ':' + TEST_NAME));
+    }
+
+    /**
+     * Tests the behavior of the lookup method for variables with an unknown
+     * prefix. These variables should not be resolved.
+     */
+    public void testLookupWithUnknownPrefix()
+    {
+        interpolator.registerLookup(TEST_PREFIX, setUpTestLookup());
+        assertNull("Variable could be resolved", interpolator
+                .lookup("UnknownPrefix:" + TEST_NAME));
+        assertNull("Variable with empty prefix could be resolved", interpolator
+                .lookup(":" + TEST_NAME));
+    }
+
+    /**
+     * Tests looking up a variable without a prefix. This should trigger the
+     * default lookup object.
+     */
+    public void testLookupDefault()
+    {
+        interpolator.setDefaultLookup(setUpTestLookup());
+        assertEquals("Wrong variable value", TEST_VALUE, interpolator
+                .lookup(TEST_NAME));
+    }
+
+    /**
+     * Tests looking up a variable without a prefix when no default lookup is
+     * specified. Result should be null in this case.
+     */
+    public void testLookupNoDefault()
+    {
+        assertNull("Variable could be resolved", 
interpolator.lookup(TEST_NAME));
+    }
+
+    /**
+     * Tests the empty variable prefix. This is a special case, but legal.
+     */
+    public void testLookupEmptyPrefix()
+    {
+        interpolator.registerLookup("", setUpTestLookup());
+        assertEquals("Wrong variable value", TEST_VALUE, interpolator
+                .lookup(":" + TEST_NAME));
+    }
+
+    /**
+     * Tests an empty variable name.
+     */
+    public void testLookupEmptyVarName()
+    {
+        Map map = new HashMap();
+        map.put("", TEST_VALUE);
+        interpolator.registerLookup(TEST_PREFIX, StrLookup.mapLookup(map));
+        assertEquals("Wrong variable value", TEST_VALUE, interpolator
+                .lookup(TEST_PREFIX + ":"));
+    }
+
+    /**
+     * Tests an empty variable name without a prefix.
+     */
+    public void testLookupDefaultEmptyVarName()
+    {
+        Map map = new HashMap();
+        map.put("", TEST_VALUE);
+        interpolator.setDefaultLookup(StrLookup.mapLookup(map));
+        assertEquals("Wrong variable value", TEST_VALUE, interpolator
+                .lookup(""));
+    }
+
+    /**
+     * Tests looking up a null variable. Result shoult be null, too.
+     */
+    public void testLookupNull()
+    {
+        assertNull("Could resolve null variable", interpolator.lookup(null));
+    }
+
+    /**
+     * Creates a lookup object that can resolve the test variable.
+     *
+     * @return the test lookup object
+     */
+    private StrLookup setUpTestLookup()
+    {
+        Map map = new HashMap();
+        map.put(TEST_NAME, TEST_VALUE);
+        return StrLookup.mapLookup(map);
+    }
+
+    /**
+     * Tests whether system properties can be correctly resolved.
+     */
+    public void testLookupSysProperties()
+    {
+        Properties sysProps = System.getProperties();
+        for (Iterator it = sysProps.keySet().iterator(); it.hasNext();)
+        {
+            String key = (String) it.next();
+            assertEquals("Wrong value for system property " + key, sysProps
+                    .getProperty(key), interpolator
+                    .lookup(ConfigurationInterpolator.PREFIX_SYSPROPERTIES
+                            + ":" + key));
+        }
+    }
+}

Propchange: 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/interpol/TestConfigurationInterpolator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/interpol/TestConfigurationInterpolator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/interpol/TestConfigurationInterpolator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



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

Reply via email to