You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2013/01/21 22:15:02 UTC

svn commit: r1436623 - in /commons/proper/configuration/trunk/src: main/java/org/apache/commons/configuration/interpol/InterpolatorSpecification.java test/java/org/apache/commons/configuration/interpol/TestInterpolatorSpecification.java

Author: oheger
Date: Mon Jan 21 21:15:01 2013
New Revision: 1436623

URL: http://svn.apache.org/viewvc?rev=1436623&view=rev
Log:
Added a new InterpolatorSpecification class.

Added:
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/interpol/InterpolatorSpecification.java   (with props)
    commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/interpol/TestInterpolatorSpecification.java   (with props)

Added: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/interpol/InterpolatorSpecification.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/interpol/InterpolatorSpecification.java?rev=1436623&view=auto
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/interpol/InterpolatorSpecification.java (added)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/interpol/InterpolatorSpecification.java Mon Jan 21 21:15:01 2013
@@ -0,0 +1,312 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * <p>
+ * A simple value class defining a {@link ConfigurationInterpolator}.
+ * </p>
+ * <p>
+ * Objects of this class can be used for creating new
+ * {@code ConfigurationInterpolator} instances; they contain all required
+ * properties. It is either possible to set a fully initialized
+ * {@code ConfigurationInterpolator} directly which can be used as is.
+ * Alternatively, some or all properties of an instance to be newly created can
+ * be set. These properties include
+ * <ul>
+ * <li>a map with {@code Lookup} objects associated with a specific prefix</li>
+ * <li>a collection with default {@code Lookup} objects (without a prefix)</li>
+ * <li>a parent {@code ConfigurationInterpolator}</li>
+ * </ul>
+ * </p>
+ * <p>
+ * When setting up a configuration it is possible to define the
+ * {@code ConfigurationInterpolator} in terms of this class. The configuration
+ * will then either use the {@code ConfigurationInterpolator} instance
+ * explicitly defined in the {@code InterpolatorSpecification} instance or
+ * create a new one.
+ * </p>
+ * <p>
+ * Instances are not created directly, but using the nested {@code Builder}
+ * class. They are then immutable.
+ * </p>
+ *
+ * @version $Id$
+ * @since 2.0
+ */
+public final class InterpolatorSpecification
+{
+    /** The {@code ConfigurationInterpolator} instance to be used directly. */
+    private final ConfigurationInterpolator interpolator;
+
+    /** The parent {@code ConfigurationInterpolator}. */
+    private final ConfigurationInterpolator parentInterpolator;
+
+    /** The map with prefix lookups. */
+    private final Map<String, Lookup> prefixLookups;
+
+    /** The collection with default lookups. */
+    private final Collection<Lookup> defaultLookups;
+
+    /**
+     * Creates a new instance of {@code InterpolatorSpecification} with the
+     * properties defined by the given builder object.
+     *
+     * @param builder the builder
+     */
+    private InterpolatorSpecification(Builder builder)
+    {
+        interpolator = builder.interpolator;
+        parentInterpolator = builder.parentInterpolator;
+        prefixLookups =
+                Collections.unmodifiableMap(new HashMap<String, Lookup>(
+                        builder.prefixLookups));
+        defaultLookups =
+                Collections.unmodifiableCollection(new ArrayList<Lookup>(
+                        builder.defLookups));
+    }
+
+    /**
+     * Returns the {@code ConfigurationInterpolator} instance to be used
+     * directly.
+     *
+     * @return the {@code ConfigurationInterpolator} (can be <b>null</b>)
+     */
+    public ConfigurationInterpolator getInterpolator()
+    {
+        return interpolator;
+    }
+
+    /**
+     * Returns the parent {@code ConfigurationInterpolator} object.
+     *
+     * @return the parent {@code ConfigurationInterpolator} (can be <b>null</b>)
+     */
+    public ConfigurationInterpolator getParentInterpolator()
+    {
+        return parentInterpolator;
+    }
+
+    /**
+     * Returns a map with prefix lookups. The keys of the map are the prefix
+     * strings, its values are the corresponding {@code Lookup} objects.
+     *
+     * @return the prefix lookups for a new {@code ConfigurationInterpolator}
+     *         instance (never <b>null</b>)
+     */
+    public Map<String, Lookup> getPrefixLookups()
+    {
+        return prefixLookups;
+    }
+
+    /**
+     * Returns a collection with the default lookups.
+     *
+     * @return the default lookups for a new {@code ConfigurationInterpolator}
+     *         instance (never <b>null</b>)
+     */
+    public Collection<Lookup> getDefaultLookups()
+    {
+        return defaultLookups;
+    }
+
+    /**
+     * <p<A <em>builder</em> class for creating instances of
+     * {@code InterpolatorSpecification}.</p>
+     * <p>
+     * This class provides a fluent API for defining the various properties of
+     * an {@code InterpolatorSpecification} object. <em>Note:</em> This builder
+     * class is not thread-safe.
+     * </p>
+     */
+    public static class Builder
+    {
+        /** A map with prefix lookups. */
+        private final Map<String, Lookup> prefixLookups;
+
+        /** A collection with default lookups. */
+        private final Collection<Lookup> defLookups;
+
+        /** The {@code ConfigurationInterpolator}. */
+        private ConfigurationInterpolator interpolator;
+
+        /** The parent {@code ConfigurationInterpolator}. */
+        private ConfigurationInterpolator parentInterpolator;
+
+        public Builder()
+        {
+            prefixLookups = new HashMap<String, Lookup>();
+            defLookups = new LinkedList<Lookup>();
+        }
+
+        /**
+         * Adds a {@code Lookup} object for a given prefix.
+         *
+         * @param prefix the prefix (must not be <b>null</b>)
+         * @param lookup the {@code Lookup} (must not be <b>null</b>)
+         * @return a reference to this builder for method chaining
+         * @throws IllegalArgumentException if a required parameter is missing
+         */
+        public Builder withPrefixLookup(String prefix, Lookup lookup)
+        {
+            if (prefix == null)
+            {
+                throw new IllegalArgumentException("Prefix must not be null!");
+            }
+            checkLookup(lookup);
+            prefixLookups.put(prefix, lookup);
+            return this;
+        }
+
+        /**
+         * Adds the content of the given map to the prefix lookups managed by
+         * this builder. The map can be <b>null</b>, then this method has no
+         * effect.
+         *
+         * @param lookups the map with prefix lookups to be added
+         * @return a reference to this builder for method chaining
+         * @throws IllegalArgumentException if the map contains <b>null</b>
+         *         values
+         */
+        public Builder withPrefixLookups(Map<String, ? extends Lookup> lookups)
+        {
+            if (lookups != null)
+            {
+                for (Map.Entry<String, ? extends Lookup> e : lookups.entrySet())
+                {
+                    withPrefixLookup(e.getKey(), e.getValue());
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Adds the given {@code Lookup} object to the list of default lookups.
+         *
+         * @param lookup the {@code Lookup} (must not be <b>null</b>)
+         * @return a reference to this builder for method chaining
+         * @throws IllegalArgumentException if the {@code Lookup} is <b>null</b>
+         */
+        public Builder withDefaultLookup(Lookup lookup)
+        {
+            checkLookup(lookup);
+            defLookups.add(lookup);
+            return this;
+        }
+
+        /**
+         * Adds the content of the given collection to the default lookups
+         * managed by this builder. The collection can be <b>null</b>, then this
+         * method has no effect.
+         *
+         * @param lookups the collection with lookups to be added
+         * @return a reference to this builder for method chaining
+         * @throws IllegalArgumentException if the collection contains
+         *         <b>null</b> entries
+         */
+        public Builder withDefaultLookups(Collection<? extends Lookup> lookups)
+        {
+            if (lookups != null)
+            {
+                for (Lookup l : lookups)
+                {
+                    withDefaultLookup(l);
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Sets the {@code ConfigurationInterpolator} instance for the
+         * {@code InterpolatorSpecification}. This means that a
+         * {@code ConfigurationInterpolator} has been created and set up
+         * externally and can be used directly.
+         *
+         * @param ci the {@code ConfigurationInterpolator} (can be <b>null</b>)
+         * @return a reference to this builder for method chaining
+         */
+        public Builder withInterpolator(ConfigurationInterpolator ci)
+        {
+            interpolator = ci;
+            return this;
+        }
+
+        /**
+         * Sets an optional parent {@code ConfigurationInterpolator}. If
+         * defined, this object is set as parent of a newly created
+         * {@code ConfigurationInterpolator} instance.
+         *
+         * @param parent the parent {@code ConfigurationInterpolator} (can be
+         *        <b>null</b>)
+         * @return a reference to this builder for method chaining
+         */
+        public Builder withParentInterpolator(ConfigurationInterpolator parent)
+        {
+            parentInterpolator = parent;
+            return this;
+        }
+
+        /**
+         * Creates a new {@code InterpolatorSpecification} instance with the
+         * properties set so far. After that this builder instance is reset so
+         * that it can be reused for creating further specification objects.
+         *
+         * @return the newly created {@code InterpolatorSpecification}
+         */
+        public InterpolatorSpecification create()
+        {
+            InterpolatorSpecification spec =
+                    new InterpolatorSpecification(this);
+            reset();
+            return spec;
+        }
+
+        /**
+         * Removes all data from this builder. Afterwards it can be used to
+         * define a brand new {@code InterpolatorSpecification} object.
+         */
+        public void reset()
+        {
+            interpolator = null;
+            parentInterpolator = null;
+            prefixLookups.clear();
+            defLookups.clear();
+        }
+
+        /**
+         * Helper method for checking a lookup. Throws an exception if the
+         * lookup is <b>null</b>.
+         *
+         * @param lookup the lookup to be checked
+         * @throws IllegalArgumentException if the lookup is <b>null</b>
+         */
+        private static void checkLookup(Lookup lookup)
+        {
+            if (lookup == null)
+            {
+                throw new IllegalArgumentException("Lookup must not be null!");
+            }
+        }
+    }
+}

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

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

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

Added: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/interpol/TestInterpolatorSpecification.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/interpol/TestInterpolatorSpecification.java?rev=1436623&view=auto
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/interpol/TestInterpolatorSpecification.java (added)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/interpol/TestInterpolatorSpecification.java Mon Jan 21 21:15:01 2013
@@ -0,0 +1,264 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@code InterpolatorSpecification}.
+ *
+ * @version $Id$
+ */
+public class TestInterpolatorSpecification
+{
+    /** Constant for a prefix for a prefix lookup. */
+    private static final String PREFIX1 = "p1";
+
+    /** Constant for another prefix for a prefix lookup. */
+    private static final String PREFIX2 = "p2";
+
+    /** The builder for creating new instances. */
+    private InterpolatorSpecification.Builder builder;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        builder = new InterpolatorSpecification.Builder();
+    }
+
+    /**
+     * Convenience method for creating a mock object.
+     *
+     * @param cls the class of the mock
+     * @param <T> the type of the mock
+     * @return the mock
+     */
+    private static <T> T createMock(Class<T> cls)
+    {
+        T mock = EasyMock.createMock(cls);
+        EasyMock.replay(mock);
+        return mock;
+    }
+
+    /**
+     * Convenience method for creating a mock lookup.
+     *
+     * @return the mock lookup
+     */
+    private static Lookup createLookup()
+    {
+        return createMock(Lookup.class);
+    }
+
+    /**
+     * Checks whether the given test object contains the expected prefix
+     * lookups.
+     *
+     * @param spec the object to be tested
+     * @param prefLook1 prefix lookup 1
+     * @param prefLook2 prefix lookup 2
+     */
+    private static void checkPrefixLookups(InterpolatorSpecification spec,
+            Lookup prefLook1, Lookup prefLook2)
+    {
+        assertEquals("Wrong number of prefix lookups", 2, spec
+                .getPrefixLookups().size());
+        assertSame("Wrong prefix lookup 1", prefLook1, spec.getPrefixLookups()
+                .get(PREFIX1));
+        assertSame("Wrong prefix lookup 2", prefLook2, spec.getPrefixLookups()
+                .get(PREFIX2));
+    }
+
+    /**
+     * Checks whether the given test object contains the expected default
+     * lookups.
+     *
+     * @param spec the object to be tested
+     * @param defLook1 default lookup 1
+     * @param defLook2 default lookup 2
+     */
+    private static void checkDefaultLookups(InterpolatorSpecification spec,
+            Lookup defLook1, Lookup defLook2)
+    {
+        assertEquals("Wrong number of default lookups", 2, spec
+                .getDefaultLookups().size());
+        assertTrue("Wrong default lookups", spec.getDefaultLookups()
+                .containsAll(Arrays.asList(defLook1, defLook2)));
+    }
+
+    /**
+     * Tests whether an instance with all possible properties can be set.
+     */
+    @Test
+    public void testCreateInstance()
+    {
+        Lookup prefLook1 = createLookup();
+        Lookup prefLook2 = createLookup();
+        Lookup defLook1 = createLookup();
+        Lookup defLook2 = createLookup();
+        ConfigurationInterpolator interpolator =
+                createMock(ConfigurationInterpolator.class);
+        ConfigurationInterpolator parent =
+                createMock(ConfigurationInterpolator.class);
+        InterpolatorSpecification spec =
+                builder.withPrefixLookup(PREFIX1, prefLook1)
+                        .withDefaultLookup(defLook1)
+                        .withPrefixLookup(PREFIX2, prefLook2)
+                        .withParentInterpolator(parent)
+                        .withDefaultLookup(defLook2)
+                        .withInterpolator(interpolator).create();
+        assertSame("Wrong interpolator", interpolator, spec.getInterpolator());
+        assertSame("Wrong parent interpolator", parent,
+                spec.getParentInterpolator());
+        checkPrefixLookups(spec, prefLook1, prefLook2);
+        checkDefaultLookups(spec, defLook1, defLook2);
+    }
+
+    /**
+     * Tests whether lookups can be set passing in full collections.
+     */
+    @Test
+    public void testCreateInstanceCollections()
+    {
+        Lookup prefLook1 = createLookup();
+        Lookup prefLook2 = createLookup();
+        Lookup defLook1 = createLookup();
+        Lookup defLook2 = createLookup();
+        Map<String, Lookup> prefixLookups = new HashMap<String, Lookup>();
+        prefixLookups.put(PREFIX1, prefLook1);
+        prefixLookups.put(PREFIX2, prefLook2);
+        InterpolatorSpecification spec =
+                builder.withPrefixLookups(prefixLookups)
+                        .withDefaultLookups(Arrays.asList(defLook1, defLook2))
+                        .create();
+        checkPrefixLookups(spec, prefLook1, prefLook2);
+        checkDefaultLookups(spec, defLook1, defLook2);
+    }
+
+    /**
+     * Tests whether a null map with prefix lookups is accepted.
+     */
+    @Test
+    public void testWithPrefixLookupsNull()
+    {
+        InterpolatorSpecification spec =
+                builder.withPrefixLookups(null).create();
+        assertTrue("No empty map with prefix lookups", spec.getPrefixLookups()
+                .isEmpty());
+    }
+
+    /**
+     * Tests whether a null collection with default lookups is accepted.
+     */
+    @Test
+    public void testWithDefaultLookupsNull()
+    {
+        InterpolatorSpecification spec =
+                builder.withDefaultLookups(null).create();
+        assertTrue("No empty default lookups collection", spec
+                .getDefaultLookups().isEmpty());
+    }
+
+    /**
+     * Tests whether a null prefix causes an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testWithPrefixLookupNoPrefix()
+    {
+        builder.withPrefixLookup(null, createLookup());
+    }
+
+    /**
+     * Tests whether a null prefix lookup causes an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testWithPrefixLookupNoLookup()
+    {
+        builder.withPrefixLookup(PREFIX1, null);
+    }
+
+    /**
+     * Tests whether a null default lookup causes an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testWithDefaultLookupNull()
+    {
+        builder.withDefaultLookup(null);
+    }
+
+    /**
+     * Tests that the map with prefix lookups cannot be modified.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testGetPrefixLookupsModify()
+    {
+        InterpolatorSpecification spec =
+                builder.withPrefixLookup(PREFIX1, createLookup()).create();
+        spec.getPrefixLookups().put(PREFIX1, createLookup());
+    }
+
+    /**
+     * Tests that the collection with default lookups cannot be modified.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testGetDefaultLookupsModify()
+    {
+        InterpolatorSpecification spec =
+                builder.withDefaultLookup(createLookup()).create();
+        spec.getDefaultLookups().add(createLookup());
+    }
+
+    /**
+     * Tests whether a builder can be reused.
+     */
+    @Test
+    public void testBuilderReuse()
+    {
+        builder.withDefaultLookup(createLookup())
+                .withInterpolator(createMock(ConfigurationInterpolator.class))
+                .withPrefixLookup("test", createLookup())
+                .withParentInterpolator(
+                        createMock(ConfigurationInterpolator.class)).create();
+        Lookup prefLook1 = createLookup();
+        Lookup prefLook2 = createLookup();
+        Lookup defLook1 = createLookup();
+        Lookup defLook2 = createLookup();
+        ConfigurationInterpolator parent =
+                createMock(ConfigurationInterpolator.class);
+        InterpolatorSpecification spec =
+                builder.withPrefixLookup(PREFIX1, prefLook1)
+                        .withPrefixLookup(PREFIX2, prefLook2)
+                        .withDefaultLookups(Arrays.asList(defLook1, defLook2))
+                        .withParentInterpolator(parent).create();
+        assertNull("Got an interpolator", spec.getInterpolator());
+        assertSame("Wrong parent interpolator", parent,
+                spec.getParentInterpolator());
+        checkPrefixLookups(spec, prefLook1, prefLook2);
+        checkDefaultLookups(spec, defLook1, defLook2);
+    }
+}

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

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

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