You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by oh...@apache.org on 2007/04/22 20:54:58 UTC
svn commit: r531254 - in /jakarta/commons/proper/configuration/trunk:
src/java/org/apache/commons/configuration/
src/test/org/apache/commons/configuration/
src/test/org/apache/commons/configuration/event/ xdocs/ xdocs/userguide/
Author: oheger
Date: Sun Apr 22 11:54:57 2007
New Revision: 531254
URL: http://svn.apache.org/viewvc?view=rev&rev=531254
Log:
CONFIGURATION-265: Auto-save of hierarchical file-based configurations is now also triggered by changes at a SubnodeConfiguration. A new event type EVENT_SUBNODE_CHANGED was introduced to report such changes to registered event listeners. Improvements of JavaDoc for HierarchicalConfiguration.
Modified:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/AbstractTestConfigurationEvents.java
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/TestHierarchicalConfigurationEvents.java
jakarta/commons/proper/configuration/trunk/xdocs/changes.xml
jakarta/commons/proper/configuration/trunk/xdocs/userguide/howto_events.xml
Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java?view=diff&rev=531254&r1=531253&r2=531254
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java Sun Apr 22 11:54:57 2007
@@ -339,6 +339,19 @@
}
/**
+ * Reacts on changes of an associated subnode configuration. If the auto
+ * save mechanism is active, the configuration must be saved.
+ *
+ * @param event the event describing the change
+ * @since 1.5
+ */
+ protected void subnodeConfigurationChanged(ConfigurationEvent event)
+ {
+ delegate.possiblySave();
+ super.subnodeConfigurationChanged(event);
+ }
+
+ /**
* Creates the file configuration delegate, i.e. the object that implements
* functionality required by the <code>FileConfiguration</code> interface.
* This base implementation will return an instance of the
Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java?view=diff&rev=531254&r1=531253&r2=531254
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java Sun Apr 22 11:54:57 2007
@@ -28,12 +28,15 @@
import org.apache.commons.collections.set.ListOrderedSet;
import org.apache.commons.collections.iterators.SingletonIterator;
+import org.apache.commons.configuration.event.ConfigurationEvent;
+import org.apache.commons.configuration.event.ConfigurationListener;
import org.apache.commons.configuration.tree.ConfigurationNode;
import org.apache.commons.configuration.tree.ConfigurationNodeVisitorAdapter;
import org.apache.commons.configuration.tree.DefaultConfigurationNode;
import org.apache.commons.configuration.tree.DefaultExpressionEngine;
import org.apache.commons.configuration.tree.ExpressionEngine;
import org.apache.commons.configuration.tree.NodeAddData;
+import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
import org.apache.commons.lang.StringUtils;
/**
@@ -94,20 +97,52 @@
* <code>getMaxIndex()</code> method that returns the maximum allowed index
* that can be added to a given property key. This method can be used to iterate
* over all values defined for a certain property.</p>
+ * <p>Since the 1.3 release of <em>Commons Configuration</em> hierarchical
+ * configurations support an <em>expression engine</em>. This expression engine
+ * is responsible for evaluating the passed in configuration keys and map them
+ * to the stored properties. The examples above are valid for the default
+ * expression engine, which is used when a new <code>HierarchicalConfiguration</code>
+ * instance is created. With the <code>setExpressionEngine()</code> method a
+ * different expression engine can be set. For instance with
+ * <code>{@link XPathExpressionEngine}</code> there is an expression engine
+ * available that supports configuration keys in XPATH syntax.</p>
+ * <p>In addition to the events common for all configuration classes hierarchical
+ * configurations support some more events that correspond to some specific
+ * methods and features:
+ * <dl><dt><em>EVENT_ADD_NODES</em></dt><dd>The <code>addNodes()</code> method
+ * was called; the event object contains the key, to which the nodes were added,
+ * and a collection with the new nodes as value.</dd>
+ * <dt><em>EVENT_CLEAR_TREE</em></dt><dd>The <code>clearTree()</code> method was
+ * called; the event object stores the key of the removed sub tree.</dd>
+ * <dt><em>EVENT_SUBNODE_CHANGED</em></dt><dd>A <code>SubnodeConfiguration</code>
+ * that was created from this configuration has been changed. The value property
+ * of the event object contains the original event object as it was sent by the
+ * subnode configuration.</dd></dl></p>
*
- * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger </a>
- * @version $Id: HierarchicalConfiguration.java,v 1.14 2004/12/02 22:05:52
- * ebourg Exp $
+ * @author Oliver Heger
+ * @version $Id$
*/
public class HierarchicalConfiguration extends AbstractConfiguration implements Serializable, Cloneable
{
- /** Constant for the clear tree event.*/
+ /**
+ * Constant for the clear tree event.
+ * @since 1.3
+ */
public static final int EVENT_CLEAR_TREE = 10;
- /** Constant for the add nodes event.*/
+ /**
+ * Constant for the add nodes event.
+ * @since 1.3
+ */
public static final int EVENT_ADD_NODES = 11;
/**
+ * Constant for the subnode configuration modified event.
+ * @since 1.5
+ */
+ public static final int EVENT_SUBNODE_CHANGED = 12;
+
+ /**
* The serial version UID.
*/
private static final long serialVersionUID = 3373812230395363192L;
@@ -564,7 +599,9 @@
*/
protected SubnodeConfiguration createSubnodeConfiguration(ConfigurationNode node)
{
- return new SubnodeConfiguration(this, node);
+ SubnodeConfiguration result = new SubnodeConfiguration(this, node);
+ registerSubnodeConfiguration(result);
+ return result;
}
/**
@@ -583,6 +620,39 @@
SubnodeConfiguration result = createSubnodeConfiguration(node);
result.setSubnodeKey(subnodeKey);
return result;
+ }
+
+ /**
+ * This method is always called when a subnode configuration created from
+ * this configuration has been modified. This implementation transforms the
+ * received event into an event of type <code>EVENT_SUBNODE_CHANGED</code>
+ * and notifies the registered listeners.
+ *
+ * @param event the event describing the change
+ * @since 1.5
+ */
+ protected void subnodeConfigurationChanged(ConfigurationEvent event)
+ {
+ fireEvent(EVENT_SUBNODE_CHANGED, null, event, event.isBeforeUpdate());
+ }
+
+ /**
+ * Registers this instance at the given subnode configuration. This
+ * implementation will register a change listener, so that modifications of
+ * the subnode configuration can be tracked.
+ *
+ * @param config the subnode configuration
+ * @since 1.5
+ */
+ void registerSubnodeConfiguration(SubnodeConfiguration config)
+ {
+ config.addConfigurationListener(new ConfigurationListener()
+ {
+ public void configurationChanged(ConfigurationEvent event)
+ {
+ subnodeConfigurationChanged(event);
+ }
+ });
}
/**
Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java?view=diff&rev=531254&r1=531253&r2=531254
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java Sun Apr 22 11:54:57 2007
@@ -245,7 +245,9 @@
*/
protected SubnodeConfiguration createSubnodeConfiguration(ConfigurationNode node)
{
- return new SubnodeConfiguration(getParent(), node);
+ SubnodeConfiguration result = new SubnodeConfiguration(getParent(), node);
+ getParent().registerSubnodeConfiguration(result);
+ return result;
}
/**
Modified: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java?view=diff&rev=531254&r1=531253&r2=531254
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java Sun Apr 22 11:54:57 2007
@@ -33,7 +33,6 @@
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
-import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.apache.commons.configuration.reloading.InvariantReloadingStrategy;
import org.apache.commons.configuration.tree.ConfigurationNode;
import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
@@ -510,7 +509,7 @@
public void testAutoSave() throws Exception
{
- conf.setFile(new File("target/testsave.xml"));
+ conf.setFile(testSaveConf);
assertFalse(conf.isAutoSave());
conf.setAutoSave(true);
assertTrue(conf.isAutoSave());
@@ -1026,6 +1025,43 @@
}
/**
+ * Tests whether the auto save mechanism is triggered by changes at a
+ * subnode configuration.
+ */
+ public void testAutoSaveWithSubnodeConfig() throws ConfigurationException
+ {
+ final String newValue = "I am autosaved";
+ conf.setFile(testSaveConf);
+ conf.setAutoSave(true);
+ Configuration sub = conf.configurationAt("element2.subelement");
+ sub.setProperty("subsubelement", newValue);
+ assertEquals("Change not visible to parent", newValue, conf
+ .getString("element2.subelement.subsubelement"));
+ XMLConfiguration conf2 = new XMLConfiguration(testSaveConf);
+ assertEquals("Change was not saved", newValue, conf2
+ .getString("element2.subelement.subsubelement"));
+ }
+
+ /**
+ * Tests whether a subnode configuration created from another subnode
+ * configuration of a XMLConfiguration can trigger the auto save mechanism.
+ */
+ public void testAutoSaveWithSubSubnodeConfig() throws ConfigurationException
+ {
+ final String newValue = "I am autosaved";
+ conf.setFile(testSaveConf);
+ conf.setAutoSave(true);
+ SubnodeConfiguration sub1 = conf.configurationAt("element2");
+ SubnodeConfiguration sub2 = sub1.configurationAt("subelement");
+ sub2.setProperty("subsubelement", newValue);
+ assertEquals("Change not visible to parent", newValue, conf
+ .getString("element2.subelement.subsubelement"));
+ XMLConfiguration conf2 = new XMLConfiguration(testSaveConf);
+ assertEquals("Change was not saved", newValue, conf2
+ .getString("element2.subelement.subsubelement"));
+ }
+
+ /**
* Prepares a configuration object for testing a reload operation.
*
* @return the initialized configuration
@@ -1036,14 +1072,7 @@
removeTestFile();
conf.save(testSaveConf);
XMLConfiguration c = new XMLConfiguration(testSaveConf);
- c.setReloadingStrategy(new FileChangedReloadingStrategy()
- {
- // Report always a change
- protected boolean hasChanged()
- {
- return true;
- }
- });
+ c.setReloadingStrategy(new FileAlwaysReloadingStrategy());
conf.setProperty("test(0).entity", "newValue");
conf.save(testSaveConf);
return c;
Modified: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/AbstractTestConfigurationEvents.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/AbstractTestConfigurationEvents.java?view=diff&rev=531254&r1=531253&r2=531254
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/AbstractTestConfigurationEvents.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/AbstractTestConfigurationEvents.java Sun Apr 22 11:54:57 2007
@@ -218,14 +218,27 @@
public void checkEvent(int type, String propName, Object propValue,
boolean before)
{
- assertFalse("Too few events received", events.isEmpty());
- ConfigurationEvent e = (ConfigurationEvent) events.removeFirst();
- assertEquals("Wrong event source", config, e.getSource());
- assertEquals("Wrong event type", type, e.getType());
+ ConfigurationEvent e = nextEvent(type);
assertEquals("Wrong property name", propName, e.getPropertyName());
assertEquals("Wrong property value", propValue, e
.getPropertyValue());
assertEquals("Wrong before flag", before, e.isBeforeUpdate());
+ }
+
+ /**
+ * Returns the next received event and checks for the expected type.
+ * This method can be used instead of <code>checkEvent()</code> for
+ * comparing complex event values.
+ * @param expectedType the expected type of the event
+ * @return the event object
+ */
+ public ConfigurationEvent nextEvent(int expectedType)
+ {
+ assertFalse("Too few events received", events.isEmpty());
+ ConfigurationEvent e = (ConfigurationEvent) events.removeFirst();
+ assertEquals("Wrong event source", config, e.getSource());
+ assertEquals("Wrong event type", expectedType, e.getType());
+ return e;
}
/**
Modified: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/TestHierarchicalConfigurationEvents.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/TestHierarchicalConfigurationEvents.java?view=diff&rev=531254&r1=531253&r2=531254
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/TestHierarchicalConfigurationEvents.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/event/TestHierarchicalConfigurationEvents.java Sun Apr 22 11:54:57 2007
@@ -21,6 +21,7 @@
import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.SubnodeConfiguration;
import org.apache.commons.configuration.tree.DefaultConfigurationNode;
/**
@@ -78,5 +79,45 @@
((HierarchicalConfiguration) config).addNodes(TEST_PROPNAME,
new ArrayList());
l.done();
+ }
+
+ /**
+ * Tests whether manipulations of a subnode configuration trigger correct
+ * events.
+ */
+ public void testSubnodeChangedEvent()
+ {
+ SubnodeConfiguration sub = ((HierarchicalConfiguration) config)
+ .configurationAt(EXIST_PROPERTY);
+ sub.addProperty("newProp", "newValue");
+ checkSubnodeEvent(l
+ .nextEvent(HierarchicalConfiguration.EVENT_SUBNODE_CHANGED),
+ true);
+ checkSubnodeEvent(l
+ .nextEvent(HierarchicalConfiguration.EVENT_SUBNODE_CHANGED),
+ false);
+ l.done();
+ }
+
+ /**
+ * Tests whether a received event contains a correct subnode event.
+ *
+ * @param event the event object
+ * @param before the expected before flag
+ */
+ private void checkSubnodeEvent(ConfigurationEvent event, boolean before)
+ {
+ assertEquals("Wrong before flag of nesting event", before, event
+ .isBeforeUpdate());
+ assertTrue("No subnode event found in value",
+ event.getPropertyValue() instanceof ConfigurationEvent);
+ ConfigurationEvent evSub = (ConfigurationEvent) event
+ .getPropertyValue();
+ assertEquals("Wrong event type",
+ HierarchicalConfiguration.EVENT_ADD_PROPERTY, evSub.getType());
+ assertEquals("Wrong property name", "newProp", evSub.getPropertyName());
+ assertEquals("Wrong property value", "newValue", evSub
+ .getPropertyValue());
+ assertEquals("Wrong before flag", before, evSub.isBeforeUpdate());
}
}
Modified: jakarta/commons/proper/configuration/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/xdocs/changes.xml?view=diff&rev=531254&r1=531253&r2=531254
==============================================================================
--- jakarta/commons/proper/configuration/trunk/xdocs/changes.xml (original)
+++ jakarta/commons/proper/configuration/trunk/xdocs/changes.xml Sun Apr 22 11:54:57 2007
@@ -23,6 +23,12 @@
<body>
<release version="1.5-SNAPSHOT" date="in SVN" description="">
+ <action dev="oheger" type="update" issue="CONFIGURATION-265">
+ For hierarchical file-based configurations the auto-save mechanism is
+ now also triggered if a subnode configuration is changed. In such a case
+ the new event type EVENT_SUBNODE_CHANGED will be sent to registered
+ listeners.
+ </action>
<action dev="oheger" type="update" issue="CONFIGURATION-266" due-to="Tobias Noebel">
ConfigurationInterpolator now also invokes the default lookup object for
variables with a prefix that could not be resolved by their associated
Modified: jakarta/commons/proper/configuration/trunk/xdocs/userguide/howto_events.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/xdocs/userguide/howto_events.xml?view=diff&rev=531254&r1=531253&r2=531254
==============================================================================
--- jakarta/commons/proper/configuration/trunk/xdocs/userguide/howto_events.xml (original)
+++ jakarta/commons/proper/configuration/trunk/xdocs/userguide/howto_events.xml Sun Apr 22 11:54:57 2007
@@ -80,8 +80,17 @@
<dt>AbstractFileConfiguration</dt>
<dd>EVENT_RELOAD (the configuration was reloaded)</dd>
<dt>HierarchicalConfiguration</dt>
- <dd>EVENT_ADD_NODES (the <code>addNodes()</code> method was called),
- EVENT_CLEAR_TREE (the <code>clearTree()</code> method was called)</dd>
+ <dd>EVENT_ADD_NODES (the <code>addNodes()</code> method was called;
+ the event object contains the key, to which the nodes were added, and
+ a collection with the new nodes as value),
+ EVENT_CLEAR_TREE (the <code>clearTree()</code> method was called; the
+ event object stores the key of the removed sub tree),
+ EVENT_SUBNODE_CHANGED (a <code>SubnodeConfiguration</code> that was
+ created from this configuration has been changed. The value property
+ of the event object contains the original event object as it was sent by
+ the subnode configuration. <em>Note: At the moment it is not possible
+ to map the property key as it was received from the subnode configuration
+ into the namespace of the parent configuration.)</em></dd>
</dl>
</p>
</subsection>
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org