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