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 2012/12/26 16:52:27 UTC
svn commit: r1425960 - in /commons/proper/configuration/trunk/src:
main/java/org/apache/commons/configuration/AbstractConfiguration.java
test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java
Author: oheger
Date: Wed Dec 26 15:52:27 2012
New Revision: 1425960
URL: http://svn.apache.org/viewvc?rev=1425960&view=rev
Log:
[CONFIGURATION-518] Added set methods to AbstractConfiguration to manipulate the Lookup objects of the current ConfigurationInterpolator.
Modified:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java
Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java?rev=1425960&r1=1425959&r2=1425960&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java Wed Dec 26 15:52:27 2012
@@ -30,6 +30,7 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.configuration.event.BaseEventSource;
import org.apache.commons.configuration.event.ConfigurationErrorEvent;
@@ -145,7 +146,7 @@ public abstract class AbstractConfigurat
private boolean throwExceptionOnMissing;
/** Stores a reference to the object that handles variable interpolation. */
- private volatile ConfigurationInterpolator interpolator;
+ private final AtomicReference<ConfigurationInterpolator> interpolator;
/** Stores the logger.*/
private Log log;
@@ -155,6 +156,7 @@ public abstract class AbstractConfigurat
*/
public AbstractConfiguration()
{
+ interpolator = new AtomicReference<ConfigurationInterpolator>();
setLogger(null);
installDefaultInterpolator();
}
@@ -294,7 +296,7 @@ public abstract class AbstractConfigurat
*/
public ConfigurationInterpolator getInterpolator()
{
- return interpolator;
+ return interpolator.get();
}
/**
@@ -306,7 +308,7 @@ public abstract class AbstractConfigurat
*/
public final void setInterpolator(ConfigurationInterpolator ci)
{
- interpolator = ci;
+ interpolator.set(ci);
}
/**
@@ -329,6 +331,74 @@ public abstract class AbstractConfigurat
}
/**
+ * Registers all {@code Lookup} objects in the given map at the current
+ * {@code ConfigurationInterpolator} of this configuration. The set of
+ * default lookup objects (for variables without a prefix) is not modified
+ * by this method. If this configuration does not have a
+ * {@code ConfigurationInterpolator}, a new instance is created. Note: This
+ * method is mainly intended to be used for initializing a configuration
+ * when it is created by a builder. Normal client code should better call
+ * {@link #installInterpolator(Map, Collection)} to define the
+ * {@code ConfigurationInterpolator} in a single step.
+ *
+ * @param lookups a map with new {@code Lookup} objects and their prefixes
+ * (may be <b>null</b>)
+ */
+ public final void setPrefixLookups(Map<String, ? extends Lookup> lookups)
+ {
+ boolean success;
+ do
+ {
+ // do this in a loop because the ConfigurationInterpolator
+ // instance may be changed by another thread
+ ConfigurationInterpolator ciOld = getInterpolator();
+ ConfigurationInterpolator ciNew =
+ (ciOld != null) ? ciOld : new ConfigurationInterpolator();
+ ciNew.registerLookups(lookups);
+ success = interpolator.compareAndSet(ciOld, ciNew);
+ } while (!success);
+ }
+
+ /**
+ * Adds all {@code Lookup} objects in the given collection as default
+ * lookups (i.e. lookups without a variable prefix) to the
+ * {@code ConfigurationInterpolator} object of this configuration. In
+ * addition, it adds a specialized default {@code Lookup} object which
+ * queries this {@code Configuration}. The set of {@code Lookup} objects
+ * with prefixes is not modified by this method. If this configuration does
+ * not have a {@code ConfigurationInterpolator}, a new instance is created.
+ * Note: This method is mainly intended to be used for initializing a
+ * configuration when it is created by a builder. Normal client code should
+ * better call {@link #installInterpolator(Map, Collection)} to define the
+ * {@code ConfigurationInterpolator} in a single step.
+ *
+ * @param lookups the collection with default {@code Lookup} objects to be
+ * added
+ */
+ public final void setDefaultLookups(Collection<? extends Lookup> lookups)
+ {
+ boolean success;
+ do
+ {
+ ConfigurationInterpolator ciOld = getInterpolator();
+ ConfigurationInterpolator ciNew =
+ (ciOld != null) ? ciOld : new ConfigurationInterpolator();
+ Lookup confLookup = findConfigurationLookup(ciNew);
+ if (confLookup == null)
+ {
+ confLookup = new ConfigurationLookup(this);
+ }
+ else
+ {
+ ciNew.removeDefaultLookup(confLookup);
+ }
+ ciNew.addDefaultLookups(lookups);
+ ciNew.addDefaultLookup(confLookup);
+ success = interpolator.compareAndSet(ciOld, ciNew);
+ } while (!success);
+ }
+
+ /**
* Creates a default {@code ConfigurationInterpolator} which is initialized
* with all default {@code Lookup} objects. This method is called by the
* constructor. It ensures that default interpolation works for every new
@@ -345,6 +415,30 @@ public abstract class AbstractConfigurat
}
/**
+ * Finds a {@code ConfigurationLookup} pointing to this configuration in the
+ * default lookups of the specified {@code ConfigurationInterpolator}. This
+ * method is called to ensure that there is exactly one default lookup
+ * querying this configuration.
+ *
+ * @param ci the {@code ConfigurationInterpolator} in question
+ * @return the found {@code Lookup} object or <b>null</b>
+ */
+ private Lookup findConfigurationLookup(ConfigurationInterpolator ci)
+ {
+ for (Lookup l : ci.getDefaultLookups())
+ {
+ if (l instanceof ConfigurationLookup)
+ {
+ if (this == ((ConfigurationLookup) l).getConfiguration())
+ {
+ return l;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the logger used by this configuration object.
*
* @return the logger
Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java?rev=1425960&r1=1425959&r2=1425960&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java Wed Dec 26 15:52:27 2012
@@ -17,11 +17,13 @@
package org.apache.commons.configuration;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -30,6 +32,8 @@ import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.configuration.event.ConfigurationEvent;
import org.apache.commons.configuration.event.ConfigurationListener;
+import org.apache.commons.configuration.interpol.Lookup;
+import org.easymock.EasyMock;
import org.junit.Test;
/**
@@ -281,6 +285,103 @@ public class TestAbstractConfigurationBa
}
/**
+ * Tests whether prefix lookups can be added to an existing
+ * {@code ConfigurationInterpolator}.
+ */
+ @Test
+ public void testSetPrefixLookupsExistingInterpolator()
+ {
+ Lookup look = EasyMock.createMock(Lookup.class);
+ EasyMock.replay(look);
+ AbstractConfiguration config =
+ new TestConfigurationImpl(new PropertiesConfiguration());
+ int count = config.getInterpolator().getLookups().size();
+ Map<String, Lookup> lookups = new HashMap<String, Lookup>();
+ lookups.put("test", look);
+ config.setPrefixLookups(lookups);
+ Map<String, Lookup> lookups2 = config.getInterpolator().getLookups();
+ assertEquals("Not added", count + 1, lookups2.size());
+ assertSame("Not found", look, lookups2.get("test"));
+ }
+
+ /**
+ * Tests whether prefix lookups can be added if no
+ * {@code ConfigurationInterpolator} exists yet.
+ */
+ @Test
+ public void testSetPrefixLookupsNoInterpolator()
+ {
+ Lookup look = EasyMock.createMock(Lookup.class);
+ EasyMock.replay(look);
+ AbstractConfiguration config =
+ new TestConfigurationImpl(new PropertiesConfiguration());
+ config.setInterpolator(null);
+ config.setPrefixLookups(Collections.singletonMap("test", look));
+ Map<String, Lookup> lookups = config.getInterpolator().getLookups();
+ assertEquals("Wrong number of lookups", 1, lookups.size());
+ assertSame("Not found", look, lookups.get("test"));
+ }
+
+ /**
+ * Tests whether default lookups can be added to an already existing
+ * {@code ConfigurationInterpolator}.
+ */
+ @Test
+ public void testSetDefaultLookupsExistingInterpolator()
+ {
+ Lookup look = EasyMock.createMock(Lookup.class);
+ EasyMock.replay(look);
+ AbstractConfiguration config =
+ new TestConfigurationImpl(new PropertiesConfiguration());
+ config.getInterpolator().addDefaultLookup(
+ new ConfigurationLookup(new PropertiesConfiguration()));
+ config.setDefaultLookups(Collections.singleton(look));
+ List<Lookup> lookups = config.getInterpolator().getDefaultLookups();
+ assertEquals("Wrong number of default lookups", 3, lookups.size());
+ assertSame("Wrong lookup at 1", look, lookups.get(1));
+ assertTrue("Wrong lookup at 2: " + lookups,
+ lookups.get(2) instanceof ConfigurationLookup);
+ }
+
+ /**
+ * Tests whether default lookups can be added if not
+ * {@code ConfigurationInterpolator} exists yet.
+ */
+ @Test
+ public void testSetDefaultLookupsNoInterpolator()
+ {
+ Lookup look = EasyMock.createMock(Lookup.class);
+ EasyMock.replay(look);
+ AbstractConfiguration config =
+ new TestConfigurationImpl(new PropertiesConfiguration());
+ config.setInterpolator(null);
+ config.setDefaultLookups(Collections.singleton(look));
+ List<Lookup> lookups = config.getInterpolator().getDefaultLookups();
+ assertEquals("Wrong number of default lookups", 2, lookups.size());
+ assertSame("Wrong lookup at 0", look, lookups.get(0));
+ assertTrue("Wrong lookup at 1",
+ lookups.get(1) instanceof ConfigurationLookup);
+ }
+
+ /**
+ * Tests whether a new {@code ConfigurationInterpolator} can be installed
+ * without providing custom lookups.
+ */
+ @Test
+ public void testInstallInterpolatorNull()
+ {
+ AbstractConfiguration config =
+ new TestConfigurationImpl(new PropertiesConfiguration());
+ config.installInterpolator(null, null);
+ assertTrue("Got prefix lookups", config.getInterpolator().getLookups()
+ .isEmpty());
+ List<Lookup> defLookups = config.getInterpolator().getDefaultLookups();
+ assertEquals("Wrong number of default lookups", 1, defLookups.size());
+ assertTrue("Wrong default lookup",
+ defLookups.get(0) instanceof ConfigurationLookup);
+ }
+
+ /**
* Tests getList() for single non-string values.
*/
@Test