Configuration EventsAll configuration classes derived from AbstractConfiguration allow to register event listeners, which are notified whenever the configuration's data is changed. This provides an easy means for tracking updates on a configuration. Configuration listenersObjects that are interested in update events triggered by configurations must implement the ConfigurationListener interface. This interface defines a single method configurationChanged(), which is passed a ConfigurationEvent object. The event object contains all information available about the modification, including:
For resolving the numeric event type use constants defined in AbstractConfiguration or derived classes. These constants start with the prefix EVENT_ and have a speaking name. Here is an incomplete list of available event types with the configuration classes, in which they are defined:
An exampleImplementing an event listener is quite easy. As an example we are going to define an event listener, which logs all received configuration events to the console. The class could look as follows: import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; public class ConfigurationLogListener implements ConfigurationListener { public void configurationChanged(ConfigurationEvent event) { if (!event.isBeforeUpdate()) { // only display events after the modification was done System.out.println("Received event!"); System.out.println("Type = " + event.getType()); if (event.getPropertyName() != null) { System.out.println("Property name = " + event.getPropertyName()); } if (event.getPropertyValue() != null) { System.out.println("Property value = " + event.getPropertyValue()); } } } } Now an instance of this event listener class has to be registered at a configuration object: AbstractConfiguration config = ... // somehow create the configuration ConfigurationListener listener = new ConfigurationLogListener(); config.addConfigurationListener(listener); ... config.addProperty("newProperty", "newValue"); // will fire an event Error listenersSome implementations of the Configuration interface operate on underlying storages that can throw exceptions on each property access. As an example consider DatabaseConfiguration: this configuration class issues an SQL statement for each accessed property, which can potentially cause a SQLException. In earlier versions of Commons Configuration such exceptions were simply logged and then swallowed. So for clients it was impossible to find out if something went wrong. From version 1.4 on there is a new way of dealing with those internal errors: the concept of error listeners. A configuration error listener is very similar to a regular configuration event listener. Instead of the ConfigurationListener interface it has to implement the ConfigurationErrorListener interface, which defines a single method configurationError(). In case of an internal error this method is invoked, and a ConfigurationErrorEvent with information about that error is passed. By inheriting from ConfigurationEvent ConfigurationErrorEvent supports all information that is available for normal configuration listeners, too (e.g. the event type or the property that was accessed when the problem occurred; note that the isBefore() method does not really make sense for error events because an error can only occur after something was done, so it returns always false is this context). This data can be used to find out when and where the error happened. In addition there is the getCause() method that returns the Throwable object, which generated this event (i.e. the causing exception). We can now continue our example from the previous section and make our example configuration listener also capable of tracing error events. To achieve this we let the ConfigurationLogListener class also implement the ConfigurationErrorListener interface: import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.event.ConfigurationListener; public class ConfigurationLogListener implements ConfigurationListener, ConfigurationErrorListener { public void configurationChanged(ConfigurationEvent event) { // remains unchanged, see above ... } public void configurationError(ConfigurationErrorEvent event) { System.out.println("An internal error occurred!"); // Log the standard properties of the configuration event configurationChanged(event); // Now log the exception event.getCause().printStackTrace(); } } Now the listener object has to be registered as an error listener, too. For this purpose AbstractConfiguration provides the addErrorListener() method. The following example fragment shows the registration of the log listener object: AbstractConfiguration config = ... // somehow create the configuration ConfigurationListener listener = new ConfigurationLogListener(); config.addConfigurationListener(listener); config.addErrorListener((ConfigurationErrorListener) listener); ... config.addProperty("newProperty", "newValue"); // will fire an event Note: AbstractConfiguration already implements a mechanism for writing internal errors to a logger object: It has the protected addErrorLogListener() method that can be called by derived classes to register a listener that will output all occurring internal errors using the default logger. Configuration implementations like DatabaseConfiguration that are affected by potential internal errors call this method during their initialization. So the default behavior of Commons Configuration for these classes is not changed: they still catch occurring exceptions and log them. However by registering specific error listeners it is now possible for clients to implement their own handling of such errors. |