Return-Path: X-Original-To: apmail-commons-commits-archive@minotaur.apache.org Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id EB344EB37 for ; Mon, 21 Jan 2013 21:15:23 +0000 (UTC) Received: (qmail 86571 invoked by uid 500); 21 Jan 2013 21:15:23 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 86519 invoked by uid 500); 21 Jan 2013 21:15:23 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 86512 invoked by uid 99); 21 Jan 2013 21:15:23 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 21 Jan 2013 21:15:23 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 21 Jan 2013 21:15:21 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 5CA5023888FE; Mon, 21 Jan 2013 21:15:02 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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 Date: Mon, 21 Jan 2013 21:15:02 -0000 To: commits@commons.apache.org From: oheger@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130121211502.5CA5023888FE@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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; + +/** + *

+ * A simple value class defining a {@link ConfigurationInterpolator}. + *

+ *

+ * 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 + *

    + *
  • a map with {@code Lookup} objects associated with a specific prefix
  • + *
  • a collection with default {@code Lookup} objects (without a prefix)
  • + *
  • a parent {@code ConfigurationInterpolator}
  • + *
+ *

+ *

+ * 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. + *

+ *

+ * Instances are not created directly, but using the nested {@code Builder} + * class. They are then immutable. + *

+ * + * @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 prefixLookups; + + /** The collection with default lookups. */ + private final Collection 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( + builder.prefixLookups)); + defaultLookups = + Collections.unmodifiableCollection(new ArrayList( + builder.defLookups)); + } + + /** + * Returns the {@code ConfigurationInterpolator} instance to be used + * directly. + * + * @return the {@code ConfigurationInterpolator} (can be null) + */ + public ConfigurationInterpolator getInterpolator() + { + return interpolator; + } + + /** + * Returns the parent {@code ConfigurationInterpolator} object. + * + * @return the parent {@code ConfigurationInterpolator} (can be null) + */ + 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 null) + */ + public Map getPrefixLookups() + { + return prefixLookups; + } + + /** + * Returns a collection with the default lookups. + * + * @return the default lookups for a new {@code ConfigurationInterpolator} + * instance (never null) + */ + public Collection getDefaultLookups() + { + return defaultLookups; + } + + /** + * builder class for creating instances of + * {@code InterpolatorSpecification}.

+ *

+ * This class provides a fluent API for defining the various properties of + * an {@code InterpolatorSpecification} object. Note: This builder + * class is not thread-safe. + *

+ */ + public static class Builder + { + /** A map with prefix lookups. */ + private final Map prefixLookups; + + /** A collection with default lookups. */ + private final Collection defLookups; + + /** The {@code ConfigurationInterpolator}. */ + private ConfigurationInterpolator interpolator; + + /** The parent {@code ConfigurationInterpolator}. */ + private ConfigurationInterpolator parentInterpolator; + + public Builder() + { + prefixLookups = new HashMap(); + defLookups = new LinkedList(); + } + + /** + * Adds a {@code Lookup} object for a given prefix. + * + * @param prefix the prefix (must not be null) + * @param lookup the {@code Lookup} (must not be null) + * @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 null, 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 null + * values + */ + public Builder withPrefixLookups(Map lookups) + { + if (lookups != null) + { + for (Map.Entry 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 null) + * @return a reference to this builder for method chaining + * @throws IllegalArgumentException if the {@code Lookup} is null + */ + 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 null, 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 + * null entries + */ + public Builder withDefaultLookups(Collection 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 null) + * @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 + * null) + * @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 null. + * + * @param lookup the lookup to be checked + * @throws IllegalArgumentException if the lookup is null + */ + 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 the type of the mock + * @return the mock + */ + private static T createMock(Class 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 prefixLookups = new HashMap(); + 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