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/04/12 22:24:03 UTC
svn commit: r1467445 - in /commons/proper/configuration/trunk/src:
main/java/org/apache/commons/configuration/
test/java/org/apache/commons/configuration/
Author: oheger
Date: Fri Apr 12 20:24:02 2013
New Revision: 1467445
URL: http://svn.apache.org/r1467445
Log:
[CONFIGURATION-524] Added support for cloning a ConfigurationInterpolator.
If a configuration is cloned, its interpolator has to be cloned, too, because
it typically contains a Lookup pointing to the original configuration.
AbstractConfiguration now provides default functionality for this purpose
which can be called by clone() implementations in derived classes.
BaseConfiguration already calls this method.
Modified:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseConfiguration.java
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseConfiguration.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=1467445&r1=1467444&r2=1467445&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 Fri Apr 12 20:24:02 2013
@@ -145,7 +145,7 @@ public abstract class AbstractConfigurat
private boolean throwExceptionOnMissing;
/** Stores a reference to the object that handles variable interpolation. */
- private final AtomicReference<ConfigurationInterpolator> interpolator;
+ private AtomicReference<ConfigurationInterpolator> interpolator;
/** Stores the logger.*/
private Log log;
@@ -426,6 +426,39 @@ public abstract class AbstractConfigurat
}
/**
+ * Creates a clone of the {@code ConfigurationInterpolator} used by this
+ * instance. This method can be called by {@code clone()} implementations of
+ * derived classes. Normally, the {@code ConfigurationInterpolator} of a
+ * configuration instance must not be shared with other instances because it
+ * contains a specific {@code Lookup} object pointing to the owning
+ * configuration. This has to be taken into account when cloning a
+ * configuration. This method creates a new
+ * {@code ConfigurationInterpolator} for this configuration instance which
+ * contains all lookup objects from the original
+ * {@code ConfigurationInterpolator} except for the configuration specific
+ * lookup pointing to the passed in original configuration. This one is
+ * replaced by a corresponding {@code Lookup} referring to this
+ * configuration.
+ *
+ * @param orgConfig the original configuration from which this one was
+ * cloned
+ * @since 2.0
+ */
+ protected void cloneInterpolator(AbstractConfiguration orgConfig)
+ {
+ interpolator = new AtomicReference<ConfigurationInterpolator>();
+ ConfigurationInterpolator orgInterpolator = orgConfig.getInterpolator();
+ List<Lookup> defaultLookups = orgInterpolator.getDefaultLookups();
+ Lookup lookup = findConfigurationLookup(orgInterpolator, orgConfig);
+ if (lookup != null)
+ {
+ defaultLookups.remove(lookup);
+ }
+
+ installInterpolator(orgInterpolator.getLookups(), defaultLookups);
+ }
+
+ /**
* 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
@@ -448,11 +481,26 @@ public abstract class AbstractConfigurat
*/
private Lookup findConfigurationLookup(ConfigurationInterpolator ci)
{
+ return findConfigurationLookup(ci, this);
+ }
+
+ /**
+ * Finds a {@code ConfigurationLookup} pointing to the specified
+ * configuration in the default lookups for the specified
+ * {@code ConfigurationInterpolator}.
+ *
+ * @param ci the {@code ConfigurationInterpolator} in question
+ * @param targetConf the target configuration of the searched lookup
+ * @return the found {@code Lookup} object or <b>null</b>
+ */
+ private static Lookup findConfigurationLookup(ConfigurationInterpolator ci,
+ ImmutableConfiguration targetConf)
+ {
for (Lookup l : ci.getDefaultLookups())
{
if (l instanceof ConfigurationLookup)
{
- if (this == ((ConfigurationLookup) l).getConfiguration())
+ if (targetConf == ((ConfigurationLookup) l).getConfiguration())
{
return l;
}
Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseConfiguration.java?rev=1467445&r1=1467444&r2=1467445&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseConfiguration.java Fri Apr 12 20:24:02 2013
@@ -170,22 +170,8 @@ public class BaseConfiguration extends A
try
{
BaseConfiguration copy = (BaseConfiguration) super.clone();
- // This is safe because the type of the map is known
- @SuppressWarnings("unchecked")
- Map<String, Object> clonedStore = (Map<String, Object>) ConfigurationUtils.clone(store);
- copy.store = clonedStore;
-
- // Handle collections in the map; they have to be cloned, too
- for (Map.Entry<String, Object> e : store.entrySet())
- {
- if (e.getValue() instanceof Collection)
- {
- // This is safe because the collections were created by ourselves
- @SuppressWarnings("unchecked")
- Collection<String> strList = (Collection<String>) e.getValue();
- copy.store.put(e.getKey(), new ArrayList<String>(strList));
- }
- }
+ cloneStore(copy);
+ copy.cloneInterpolator(this);
return copy;
}
@@ -195,4 +181,31 @@ public class BaseConfiguration extends A
throw new ConfigurationRuntimeException(cex);
}
}
+
+ /**
+ * Clones the internal map with the data of this configuration.
+ *
+ * @param copy the copy created by the {@code clone()} method
+ * @throws CloneNotSupportedException if the map cannot be cloned
+ */
+ private void cloneStore(BaseConfiguration copy)
+ throws CloneNotSupportedException
+ {
+ // This is safe because the type of the map is known
+ @SuppressWarnings("unchecked")
+ Map<String, Object> clonedStore = (Map<String, Object>) ConfigurationUtils.clone(store);
+ copy.store = clonedStore;
+
+ // Handle collections in the map; they have to be cloned, too
+ for (Map.Entry<String, Object> e : store.entrySet())
+ {
+ if (e.getValue() instanceof Collection)
+ {
+ // This is safe because the collections were created by ourselves
+ @SuppressWarnings("unchecked")
+ Collection<String> strList = (Collection<String>) e.getValue();
+ copy.store.put(e.getKey(), new ArrayList<String>(strList));
+ }
+ }
+ }
}
Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseConfiguration.java?rev=1467445&r1=1467444&r2=1467445&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseConfiguration.java Fri Apr 12 20:24:02 2013
@@ -800,4 +800,21 @@ public class TestBaseConfiguration
assertEquals("Wrong number of original properties", 2, config.getList(
key).size());
}
+
+ /**
+ * Tests whether interpolation works as expected after cloning.
+ */
+ @Test
+ public void testCloneInterpolation()
+ {
+ final String keyAnswer = "answer";
+ config.addProperty(keyAnswer, "The answer is ${" + KEY_NUMBER + "}.");
+ config.addProperty(KEY_NUMBER, 42);
+ BaseConfiguration clone = (BaseConfiguration) config.clone();
+ clone.setProperty(KEY_NUMBER, 43);
+ assertEquals("Wrong interpolation in original", "The answer is 42.",
+ config.getString(keyAnswer));
+ assertEquals("Wrong interpolation in clone", "The answer is 43.",
+ clone.getString(keyAnswer));
+ }
}