Author: oheger Date: Sun Apr 16 10:55:55 2006 New Revision: 394529 URL: http://svn.apache.org/viewcvs?rev=394529&view=rev Log: Added event listener support to basic configuration classes
Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/BaseConfiguration.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/MapConfiguration.java Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java?rev=394529&r1=394528&r2=394529&view=diff ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java (original) +++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java Sun Apr 16 10:55:55 2006 @@ -26,12 +26,32 @@ import org.apache.commons.collections.Predicate; import org.apache.commons.collections.iterators.FilterIterator; +import org.apache.commons.configuration.event.EventSource; import org.apache.commons.lang.BooleanUtils; /** - * Abstract configuration class. Provide basic functionality but does not store - * any data. If you want to write your own Configuration class then you should - * implement only abstract methods from this class. + * <p>Abstract configuration class. Provides basic functionality but does not + * store any data.</p> + * <p>If you want to write your own Configuration class then you should + * implement only abstract methods from this class. A lot of functionality + * needed by typical implementations of the <code>Configuration</conde> + * interface is already provided by this base class. Following is a list of + * feauters implemented here: + * <ul><li>Data conversion support. The various data types required by the + * <code>Configuration</code> interface are already handled by this base class. + * A concrete sub class only needs to provide a generic <code>getProperty()</code> + * method.</li> + * <li>Support for variable interpolation. Property values containing special + * variable tokens (like <code>${var}</code>) will be replaced by their + * corresponding values.</li> + * <li>Support for string lists. The values of properties to be added to this + * configuration are checked whether they contain a list delimiter character. If + * this is the case and if list splitting is enabled, the string is splitted and + * multiple values are added for this property.</li> + * <li>Basic event support. Whenever this configuration is modified registered + * event listeners are notified. Refer to the various <code>EVENT_XXX</code> + * constants to get an impression about which event types are supported.</li> + * </ul></p> * * @author <a href="mailto:[EMAIL PROTECTED]">Konstantin Shaposhnikov </a> * @author <a href="mailto:[EMAIL PROTECTED]">Oliver Heger </a> @@ -39,8 +59,20 @@ * @version $Id: AbstractConfiguration.java,v 1.29 2004/12/02 22:05:52 ebourg * Exp $ */ -public abstract class AbstractConfiguration implements Configuration +public abstract class AbstractConfiguration extends EventSource implements Configuration { + /** Constant for the add property event type.*/ + public static final int EVENT_ADD_PROPERTY = 1; + + /** Constant for the clear property event type.*/ + public static final int EVENT_CLEAR_PROPERTY = 2; + + /** Constant for the set property event type.*/ + public static final int EVENT_SET_PROPERTY = 3; + + /** Constant for the clear configuration event type.*/ + public static final int EVENT_CLEAR = 4; + /** start token */ protected static final String START_TOKEN = "${"; @@ -187,6 +219,8 @@ */ public void addProperty(String key, Object value) { + fireEvent(EVENT_ADD_PROPERTY, key, value, true); + if (!isDelimiterParsingDisabled()) { Iterator it = PropertyConverter.toIterator(value, getListDelimiter()); @@ -199,6 +233,8 @@ { addPropertyDirect(key, value); } + + fireEvent(EVENT_ADD_PROPERTY, key, value, false); } /** @@ -279,32 +315,74 @@ */ public void setProperty(String key, Object value) { - clearProperty(key); - addProperty(key, value); + fireEvent(EVENT_SET_PROPERTY, key, value, true); + setDetailEvents(false); + try + { + clearProperty(key); + addProperty(key, value); + } + finally + { + setDetailEvents(true); + } + fireEvent(EVENT_SET_PROPERTY, key, value, false); } /** - * [EMAIL PROTECTED] + * Removes the specified property from this configuration. This + * implementation performs some preparations and then delegates to + * <code>clearPropertyDirect()</code>, which will do the real work. + * + * @param key the key to be removed */ - public abstract void clearProperty(String key); + public void clearProperty(String key) + { + fireEvent(EVENT_CLEAR_PROPERTY, key, null, true); + clearPropertyDirect(key); + fireEvent(EVENT_CLEAR_PROPERTY, key, null, false); + } + + /** + * Removes the specified property from this configuration. This method is + * called by <code>clearProperty()</code> after it has done some + * preparations. It should be overriden in sub classes. This base + * implementation is just left empty. + * + * @param key the key to be removed + */ + protected void clearPropertyDirect(String key) + { + // override in sub classes + } /** * [EMAIL PROTECTED] */ public void clear() { - Iterator it = getKeys(); - while (it.hasNext()) + fireEvent(EVENT_CLEAR, null, null, true); + setDetailEvents(false); + try { - String key = (String) it.next(); - it.remove(); - - if (containsKey(key)) + Iterator it = getKeys(); + while (it.hasNext()) { - // workaround for Iterators that do not remove the property on calling remove() - clearProperty(key); + String key = (String) it.next(); + it.remove(); + + if (containsKey(key)) + { + // workaround for Iterators that do not remove the property on calling remove() + clearProperty(key); + } } } + finally + { + setDetailEvents(true); + } + fireEvent(EVENT_CLEAR, null, null, false); } /** Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java?rev=394529&r1=394528&r2=394529&view=diff ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java (original) +++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java Sun Apr 16 10:55:55 2006 @@ -76,6 +76,9 @@ */ public abstract class AbstractFileConfiguration extends BaseConfiguration implements FileConfiguration { + /** Constant for the configuration reload event.*/ + public static final int EVENT_RELOAD = 20; + /** Stores the file name.*/ protected String fileName; @@ -709,8 +712,18 @@ if (strategy.reloadingRequired()) { - clear(); - load(); + fireEvent(EVENT_RELOAD, null, getURL(), true); + setDetailEvents(false); + try + { + clear(); + load(); + } + finally + { + setDetailEvents(true); + } + fireEvent(EVENT_RELOAD, null, getURL(), false); // notify the strategy strategy.reloadingPerformed(); @@ -760,6 +773,31 @@ { noReload--; } + } + } + + /** + * Sends an event to all registered listeners. This implementation ensures + * that no reloads are performed while the listeners are invoked. So + * infinite loops can be avoided that can be caused by event listeners + * accessing the configuration's properties when they are invoked. + * + * @param type the event type + * @param propName the name of the property + * @param propValue the value of the property + * @param before the before update flag + */ + protected void fireEvent(int type, String propName, Object propValue, + boolean before) + { + enterNoReload(); + try + { + super.fireEvent(type, propName, propValue, before); + } + finally + { + exitNoReload(); } } Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java?rev=394529&r1=394528&r2=394529&view=diff ============================================================================== --- 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 16 10:55:55 2006 @@ -1,5 +1,5 @@ /* - * Copyright 2005 The Apache Software Foundation. + * Copyright 2005-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. @@ -24,6 +24,8 @@ import java.net.URL; import java.util.Iterator; +import org.apache.commons.configuration.event.ConfigurationEvent; +import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.reloading.ReloadingStrategy; /** @@ -44,10 +46,12 @@ /** Stores the delegate used for implementing functionality related to the * <code>FileConfiguration</code> interface. */ - private FileConfigurationDelegate delegate = createDelegate(); + private FileConfigurationDelegate delegate; protected AbstractHierarchicalFileConfiguration() { + delegate = createDelegate(); + initDelegate(delegate); } /** @@ -58,6 +62,7 @@ */ public AbstractHierarchicalFileConfiguration(String fileName) throws ConfigurationException { + this(); // store the file name delegate.setPath(fileName); @@ -73,6 +78,7 @@ */ public AbstractHierarchicalFileConfiguration(File file) throws ConfigurationException { + this(); // set the file and update the url, the base path and the file name setFile(file); @@ -91,6 +97,7 @@ */ public AbstractHierarchicalFileConfiguration(URL url) throws ConfigurationException { + this(); // set the URL and update the base path and the file name setURL(url); @@ -244,7 +251,15 @@ public void reload() { - delegate.reload(); + setDetailEvents(false); + try + { + delegate.reload(); + } + finally + { + setDetailEvents(true); + } } public String getEncoding() @@ -293,6 +308,32 @@ protected FileConfigurationDelegate createDelegate() { return new FileConfigurationDelegate(); + } + + /** + * Helper method for initializing the file configuration delegate. + * + * @param del the delegate + */ + private void initDelegate(FileConfigurationDelegate del) + { + del.addConfigurationListener(new ConfigurationListener() + { + public void configurationChanged(ConfigurationEvent event) + { + // deliver reload events to registered listeners + setDetailEvents(true); + try + { + fireEvent(event.getType(), event.getPropertyName(), event + .getPropertyValue(), event.isBeforeUpdate()); + } + finally + { + setDetailEvents(false); + } + } + }); } /** Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/BaseConfiguration.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/BaseConfiguration.java?rev=394529&r1=394528&r2=394529&view=diff ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/BaseConfiguration.java (original) +++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/BaseConfiguration.java Sun Apr 16 10:55:55 2006 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 The Apache Software Foundation. + * Copyright 2001-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. @@ -124,7 +124,7 @@ * * @param key the key to remove along with corresponding value. */ - public void clearProperty(String key) + protected void clearPropertyDirect(String key) { if (containsKey(key)) { @@ -137,7 +137,9 @@ */ public void clear() { + fireEvent(EVENT_CLEAR, null, null, true); store.clear(); + fireEvent(EVENT_CLEAR, null, null, false); } /** Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java?rev=394529&r1=394528&r2=394529&view=diff ============================================================================== --- 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 16 10:55:55 2006 @@ -100,6 +100,12 @@ */ public class HierarchicalConfiguration extends AbstractConfiguration implements Serializable, Cloneable { + /** Constant for the clear tree event.*/ + public static final int EVENT_CLEAR_TREE = 10; + + /** Constant for the add nodes event.*/ + public static final int EVENT_ADD_NODES = 11; + /** Stores the default expression engine to be used for new objects.*/ private static ExpressionEngine defaultExpressionEngine = new DefaultExpressionEngine(); @@ -315,6 +321,7 @@ return; } + fireEvent(EVENT_ADD_NODES, key, nodes, true); ConfigurationNode parent; List target = fetchNodeList(key); if (target.size() == 1) @@ -346,6 +353,7 @@ parent.addChild(child); } } + fireEvent(EVENT_ADD_NODES, key, nodes, false); } /** @@ -509,6 +517,8 @@ */ public void setProperty(String key, Object value) { + fireEvent(EVENT_SET_PROPERTY, key, value, true); + Iterator itNodes = fetchNodeList(key).iterator(); Iterator itValues; if (!isDelimiterParsingDisabled()) @@ -535,6 +545,8 @@ { clearNode((ConfigurationNode) itNodes.next()); } + + fireEvent(EVENT_SET_PROPERTY, key, value, false); } /** @@ -547,12 +559,14 @@ */ public void clearTree(String key) { + fireEvent(EVENT_CLEAR_TREE, key, null, true); List nodes = fetchNodeList(key); for (Iterator it = nodes.iterator(); it.hasNext();) { removeNode((ConfigurationNode) it.next()); } + fireEvent(EVENT_CLEAR_TREE, key, nodes, false); } /** @@ -564,12 +578,15 @@ */ public void clearProperty(String key) { + fireEvent(EVENT_CLEAR_PROPERTY, key, null, true); List nodes = fetchNodeList(key); for (Iterator it = nodes.iterator(); it.hasNext();) { clearNode((ConfigurationNode) it.next()); } + + fireEvent(EVENT_CLEAR_PROPERTY, key, null, false); } /** Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/MapConfiguration.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/MapConfiguration.java?rev=394529&r1=394528&r2=394529&view=diff ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/MapConfiguration.java (original) +++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/MapConfiguration.java Sun Apr 16 10:55:55 2006 @@ -103,7 +103,7 @@ return map.containsKey(key); } - public void clearProperty(String key) + protected void clearPropertyDirect(String key) { map.remove(key); } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]