Author: oheger
Date: Thu Oct 4 20:18:31 2012
New Revision: 1394243
URL: http://svn.apache.org/viewvc?rev=1394243&view=rev
Log:
Added support for event listeners to BasicConfigurationBuilder.
Modified:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
Modified:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java?rev=1394243&r1=1394242&r2=1394243&view=diff
==============================================================================
---
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
(original)
+++
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicConfigurationBuilder.java
Thu Oct 4 20:18:31 2012
@@ -16,6 +16,8 @@
*/
package org.apache.commons.configuration.builder;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -25,6 +27,9 @@ import org.apache.commons.configuration.
import org.apache.commons.configuration.ConfigurationRuntimeException;
import org.apache.commons.configuration.beanutils.BeanDeclaration;
import org.apache.commons.configuration.beanutils.BeanHelper;
+import org.apache.commons.configuration.event.ConfigurationErrorListener;
+import org.apache.commons.configuration.event.ConfigurationListener;
+import org.apache.commons.configuration.event.EventSource;
/**
* <p>
@@ -78,9 +83,51 @@ import org.apache.commons.configuration.
public class BasicConfigurationBuilder<T extends Configuration> implements
ConfigurationBuilder<T>
{
+ /**
+ * A dummy event source that is used for registering listeners if no
+ * compatible result object is available. This source has empty dummy
+ * implementations for listener registration methods.
+ */
+ private static final EventSource DUMMY_EVENT_SOURCE = new EventSource()
+ {
+ @Override
+ public void addConfigurationListener(ConfigurationListener l)
+ {
+ }
+
+ @Override
+ public boolean removeConfigurationListener(ConfigurationListener l)
+ {
+ return false;
+ }
+
+ @Override
+ public void addErrorListener(ConfigurationErrorListener l)
+ {
+ }
+
+ @Override
+ public boolean removeErrorListener(ConfigurationErrorListener l)
+ {
+ return false;
+ }
+ };
+
/** The class of the objects produced by this builder instance. */
private final Class<T> resultClass;
+ /**
+ * A collection with configuration listeners to be registered at newly
+ * created configuration objects.
+ */
+ private final Collection<ConfigurationListener> configListeners;
+
+ /**
+ * A collection with error listeners to be registered at newly created
+ * configuration objects.
+ */
+ private final Collection<ConfigurationErrorListener> errorListeners;
+
/** The map with current initialization parameters. */
private Map<String, Object> parameters;
@@ -121,6 +168,8 @@ public class BasicConfigurationBuilder<T
}
resultClass = resCls;
+ configListeners = new ArrayList<ConfigurationListener>();
+ errorListeners = new ArrayList<ConfigurationErrorListener>();
updateParameters(params);
}
@@ -192,6 +241,69 @@ public class BasicConfigurationBuilder<T
}
/**
+ * Adds the specified listener for {@code ConfigurationEvent}s to this
+ * builder. It is also registered at the result objects produced by this
+ * builder.
+ *
+ * @param l the listener to be registered
+ * @return a reference to this builder for method chaining
+ */
+ public synchronized BasicConfigurationBuilder<T> addConfigurationListener(
+ ConfigurationListener l)
+ {
+ configListeners.add(l);
+ fetchEventSource().addConfigurationListener(l);
+ return this;
+ }
+
+ /**
+ * Removes the specified listener for {@code ConfigurationEvent}s from this
+ * builder. It is also removed from the current result object if it exists.
+ *
+ * @param l the listener to be removed
+ * @return a reference to this builder for method chaining
+ */
+ public synchronized BasicConfigurationBuilder<T>
removeConfigurationListener(
+ ConfigurationListener l)
+ {
+ configListeners.remove(l);
+ fetchEventSource().removeConfigurationListener(l);
+ return this;
+ }
+
+ /**
+ * Adds the specified listener for {@code ConfigurationErrorEvent}s to this
+ * builder. It is also registered at the result objects produced by this
+ * builder.
+ *
+ * @param l the listener to be registered
+ * @return a reference to this builder for method chaining
+ */
+ public BasicConfigurationBuilder<T> addErrorListener(
+ ConfigurationErrorListener l)
+ {
+ errorListeners.add(l);
+ fetchEventSource().addErrorListener(l);
+ return this;
+ }
+
+ /**
+ * Removes the specified listener for {@code ConfigurationErrorEvent}s from
+ * this builder. It is also removed from the current result object if it
+ * exists.
+ *
+ * @param l the listener to be removed
+ * @return a reference to this builder for method chaining
+ */
+ public BasicConfigurationBuilder<T> removeErrorListener(
+ ConfigurationErrorListener l)
+ {
+ errorListeners.remove(l);
+ fetchEventSource().removeErrorListener(l);
+ return this;
+ }
+
+ /**
* {@inheritDoc} This implementation creates the result configuration on
* first access. Later invocations return the same object until this
builder
* is reset. The double-check idiom for lazy initialization is used (Bloch,
@@ -298,6 +410,7 @@ public class BasicConfigurationBuilder<T
protected void initResultInstance(T obj) throws ConfigurationException
{
BeanHelper.initBean(obj, getResultDeclaration());
+ registerEventListeners(obj);
}
/**
@@ -397,6 +510,37 @@ public class BasicConfigurationBuilder<T
}
/**
+ * Registers the available event listeners at the given object. This method
+ * is called for each result object created by the builder.
+ *
+ * @param obj the object to initialize
+ */
+ private void registerEventListeners(T obj)
+ {
+ EventSource evSrc = fetchEventSource(obj);
+ for (ConfigurationListener l : configListeners)
+ {
+ evSrc.addConfigurationListener(l);
+ }
+ for (ConfigurationErrorListener l : errorListeners)
+ {
+ evSrc.addErrorListener(l);
+ }
+ }
+
+ /**
+ * Returns an {@code EventSource} for the current result object. If there
is
+ * no current result or if it does not extend {@code EventSource}, a dummy
+ * event source is returned.
+ *
+ * @return the {@code EventSource} for the current result object
+ */
+ private EventSource fetchEventSource()
+ {
+ return fetchEventSource(result);
+ }
+
+ /**
* Checks whether the bean class of the given {@code BeanDeclaration}
equals
* this builder's result class. This is done to ensure that only objects of
* the expected result class are created.
@@ -413,4 +557,18 @@ public class BasicConfigurationBuilder<T
+ decl.getBeanClassName());
}
}
+
+ /**
+ * Returns an {@code EventSource} for the specified object. If the object
is
+ * an {@code EventSource}, it is returned. Otherwise, a dummy event source
+ * is returned.
+ *
+ * @param obj the object in question
+ * @return an {@code EventSource} for this object
+ */
+ private static EventSource fetchEventSource(Object obj)
+ {
+ return (obj instanceof EventSource) ? (EventSource) obj
+ : DUMMY_EVENT_SOURCE;
+ }
}
Modified:
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java?rev=1394243&r1=1394242&r2=1394243&view=diff
==============================================================================
---
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
(original)
+++
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicConfigurationBuilder.java
Thu Oct 4 20:18:31 2012
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertNot
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -34,6 +35,8 @@ import org.apache.commons.configuration.
import org.apache.commons.configuration.ConfigurationRuntimeException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.beanutils.BeanDeclaration;
+import org.apache.commons.configuration.event.ConfigurationErrorListener;
+import org.apache.commons.configuration.event.ConfigurationListener;
import org.easymock.EasyMock;
import org.junit.Test;
@@ -312,6 +315,100 @@ public class TestBasicConfigurationBuild
}
/**
+ * Tests whether configuration listeners can be added.
+ */
+ @Test
+ public void testAddConfigurationListener() throws ConfigurationException
+ {
+ ConfigurationListener l1 =
+ EasyMock.createMock(ConfigurationListener.class);
+ ConfigurationListener l2 =
+ EasyMock.createMock(ConfigurationListener.class);
+ EasyMock.replay(l1, l2);
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class)
+ .addConfigurationListener(l1);
+ PropertiesConfiguration config = builder.getConfiguration();
+ builder.addConfigurationListener(l2);
+ assertTrue("Listeners not registered", config
+ .getConfigurationListeners().containsAll(Arrays.asList(l1,
l2)));
+ }
+
+ /**
+ * Tests whether configuration listeners can be removed.
+ */
+ @Test
+ public void testRemoveConfigurationListener() throws ConfigurationException
+ {
+ ConfigurationListener l1 =
+ EasyMock.createMock(ConfigurationListener.class);
+ ConfigurationListener l2 =
+ EasyMock.createMock(ConfigurationListener.class);
+ EasyMock.replay(l1, l2);
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class)
+ .addConfigurationListener(l1).addConfigurationListener(
+ l2);
+ builder.removeConfigurationListener(l2);
+ PropertiesConfiguration config = builder.getConfiguration();
+ assertFalse("Removed listener was registered", config
+ .getConfigurationListeners().contains(l2));
+ assertTrue("Listener not registered", config
+ .getConfigurationListeners().contains(l1));
+ builder.removeConfigurationListener(l1);
+ assertFalse("Listener still registered", config
+ .getConfigurationListeners().contains(l1));
+ }
+
+ /**
+ * Tests whether error listeners can be registered.
+ */
+ @Test
+ public void testAddErrorListener() throws ConfigurationException
+ {
+ ConfigurationErrorListener l1 =
+ EasyMock.createMock(ConfigurationErrorListener.class);
+ ConfigurationErrorListener l2 =
+ EasyMock.createMock(ConfigurationErrorListener.class);
+ EasyMock.replay(l1, l2);
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class).addErrorListener(l1);
+ PropertiesConfiguration config = builder.getConfiguration();
+ builder.addErrorListener(l2);
+ assertTrue("Listeners not registered", config.getErrorListeners()
+ .containsAll(Arrays.asList(l1, l2)));
+ }
+
+ /**
+ * Tests whether error listeners can be removed.
+ */
+ @Test
+ public void testRemoveErrorListener() throws ConfigurationException
+ {
+ ConfigurationErrorListener l1 =
+ EasyMock.createMock(ConfigurationErrorListener.class);
+ ConfigurationErrorListener l2 =
+ EasyMock.createMock(ConfigurationErrorListener.class);
+ EasyMock.replay(l1, l2);
+ BasicConfigurationBuilder<PropertiesConfiguration> builder =
+ new BasicConfigurationBuilder<PropertiesConfiguration>(
+ PropertiesConfiguration.class).addErrorListener(l1)
+ .addErrorListener(l2);
+ builder.removeErrorListener(l2);
+ PropertiesConfiguration config = builder.getConfiguration();
+ assertFalse("Removed listener was registered", config
+ .getErrorListeners().contains(l2));
+ assertTrue("Listener not registered", config
+ .getErrorListeners().contains(l1));
+ builder.removeErrorListener(l1);
+ assertFalse("Listener still registered", config
+ .getErrorListeners().contains(l1));
+ }
+
+ /**
* A test thread class for testing whether the builder's result object can
* be requested concurrently.
*/