~ubuntu-branches/ubuntu/saucy/commons-configuration/saucy

« back to all changes in this revision

Viewing changes to src/main/java/org/apache/commons/configuration/event/EventSource.java

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg
  • Date: 2013-07-01 16:29:44 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20130701162944-98waq5gogha5gpn1
Tags: 1.9-1
* New upstream release
* debian/control:
  - Updated Standards-Version to 3.9.4 (no changes)
  - Use canonical URLs for the Vcs-* fields
  - Added new build dependencies (libjavacc-maven-plugin-java, junit4)
  - Upgraded the dependency on the Servlet API (2.5 -> 3.0)
  - Removed the dependency on the Activation Framework (glassfish-activation)
  - Replaced the dependency on glassfish-mail with libgnumail-java
  - Removed the unused dependencies:
    liblog4j1.2-java-doc, libmaven-assembly-plugin-java
  - Replaced the dependency on libcommons-jexl-java by libcommons-jexl2-java
* debian/watch: Changed to point the official Apache distribution server
* Removed the obsolete file debian/ant.properties
* Installed the upstream changelog in the binary packages
* Added the report plugins to maven.ignoreRules
* Added the classpath attribute to the jar manifest

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
 
3
 * contributor license agreements.  See the NOTICE file distributed with
 
4
 * this work for additional information regarding copyright ownership.
 
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
6
 * (the "License"); you may not use this file except in compliance with
 
7
 * the License.  You may obtain a copy of the License at
 
8
 *
 
9
 *     http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
11
 * Unless required by applicable law or agreed to in writing, software
 
12
 * distributed under the License is distributed on an "AS IS" BASIS,
 
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
 * See the License for the specific language governing permissions and
 
15
 * limitations under the License.
 
16
 */
 
17
package org.apache.commons.configuration.event;
 
18
 
 
19
import java.util.ArrayList;
 
20
import java.util.Collection;
 
21
import java.util.Collections;
 
22
import java.util.Iterator;
 
23
import java.util.concurrent.CopyOnWriteArrayList;
 
24
 
 
25
/**
 
26
 * <p>
 
27
 * A base class for objects that can generate configuration events.
 
28
 * </p>
 
29
 * <p>
 
30
 * This class implements functionality for managing a set of event listeners
 
31
 * that can be notified when an event occurs. It can be extended by
 
32
 * configuration classes that support the event mechanism. In this case these
 
33
 * classes only need to call the {@code fireEvent()} method when an event
 
34
 * is to be delivered to the registered listeners.
 
35
 * </p>
 
36
 * <p>
 
37
 * Adding and removing event listeners can happen concurrently to manipulations
 
38
 * on a configuration that cause events. The operations are synchronized.
 
39
 * </p>
 
40
 * <p>
 
41
 * With the {@code detailEvents} property the number of detail events can
 
42
 * be controlled. Some methods in configuration classes are implemented in a way
 
43
 * that they call other methods that can generate their own events. One example
 
44
 * is the {@code setProperty()} method that can be implemented as a
 
45
 * combination of {@code clearProperty()} and {@code addProperty()}.
 
46
 * With {@code detailEvents} set to <b>true</b>, all involved methods
 
47
 * will generate events (i.e. listeners will receive property set events,
 
48
 * property clear events, and property add events). If this mode is turned off
 
49
 * (which is the default), detail events are suppressed, so only property set
 
50
 * events will be received. Note that the number of received detail events may
 
51
 * differ for different configuration implementations.
 
52
 * {@link org.apache.commons.configuration.HierarchicalConfiguration HierarchicalConfiguration}
 
53
 * for instance has a custom implementation of {@code setProperty()},
 
54
 * which does not generate any detail events.
 
55
 * </p>
 
56
 * <p>
 
57
 * In addition to &quot;normal&quot; events, error events are supported. Such
 
58
 * events signal an internal problem that occurred during access of properties.
 
59
 * For them a special listener interface exists:
 
60
 * {@link ConfigurationErrorListener}. There is another set of
 
61
 * methods dealing with event listeners of this type. The
 
62
 * {@code fireError()} method can be used by derived classes to send
 
63
 * notifications about errors to registered observers.
 
64
 * </p>
 
65
 *
 
66
 * @author <a href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
 
67
 * @version $Id: EventSource.java 1234617 2012-01-22 21:31:01Z oheger $
 
68
 * @since 1.3
 
69
 */
 
70
public class EventSource
 
71
{
 
72
    /** A collection for the registered event listeners. */
 
73
    private Collection<ConfigurationListener> listeners;
 
74
 
 
75
    /** A collection for the registered error listeners.*/
 
76
    private Collection<ConfigurationErrorListener> errorListeners;
 
77
 
 
78
    /** A lock object for guarding access to the detail events counter. */
 
79
    private final Object lockDetailEventsCount = new Object();
 
80
 
 
81
    /** A counter for the detail events. */
 
82
    private int detailEvents;
 
83
 
 
84
    /**
 
85
     * Creates a new instance of {@code EventSource}.
 
86
     */
 
87
    public EventSource()
 
88
    {
 
89
        initListeners();
 
90
    }
 
91
 
 
92
    /**
 
93
     * Adds a configuration listener to this object.
 
94
     *
 
95
     * @param l the listener to add
 
96
     */
 
97
    public void addConfigurationListener(ConfigurationListener l)
 
98
    {
 
99
        checkListener(l);
 
100
        listeners.add(l);
 
101
    }
 
102
 
 
103
    /**
 
104
     * Removes the specified event listener so that it does not receive any
 
105
     * further events caused by this object.
 
106
     *
 
107
     * @param l the listener to be removed
 
108
     * @return a flag whether the event listener was found
 
109
     */
 
110
    public boolean removeConfigurationListener(ConfigurationListener l)
 
111
    {
 
112
        return listeners.remove(l);
 
113
    }
 
114
 
 
115
    /**
 
116
     * Returns a collection with all configuration event listeners that are
 
117
     * currently registered at this object.
 
118
     *
 
119
     * @return a collection with the registered
 
120
     * {@code ConfigurationListener}s (this collection is a snapshot
 
121
     * of the currently registered listeners; manipulating it has no effect
 
122
     * on this event source object)
 
123
     */
 
124
    public Collection<ConfigurationListener> getConfigurationListeners()
 
125
    {
 
126
        return Collections.unmodifiableCollection(new ArrayList<ConfigurationListener>(listeners));
 
127
    }
 
128
 
 
129
    /**
 
130
     * Removes all registered configuration listeners.
 
131
     */
 
132
    public void clearConfigurationListeners()
 
133
    {
 
134
        listeners.clear();
 
135
    }
 
136
 
 
137
    /**
 
138
     * Returns a flag whether detail events are enabled.
 
139
     *
 
140
     * @return a flag if detail events are generated
 
141
     */
 
142
    public boolean isDetailEvents()
 
143
    {
 
144
        return checkDetailEvents(0);
 
145
    }
 
146
 
 
147
    /**
 
148
     * Determines whether detail events should be generated. If enabled, some
 
149
     * methods can generate multiple update events. Note that this method
 
150
     * records the number of calls, i.e. if for instance
 
151
     * {@code setDetailEvents(false)} was called three times, you will
 
152
     * have to invoke the method as often to enable the details.
 
153
     *
 
154
     * @param enable a flag if detail events should be enabled or disabled
 
155
     */
 
156
    public void setDetailEvents(boolean enable)
 
157
    {
 
158
        synchronized (lockDetailEventsCount)
 
159
        {
 
160
            if (enable)
 
161
            {
 
162
                detailEvents++;
 
163
            }
 
164
            else
 
165
            {
 
166
                detailEvents--;
 
167
            }
 
168
        }
 
169
    }
 
170
 
 
171
    /**
 
172
     * Adds a new configuration error listener to this object. This listener
 
173
     * will then be notified about internal problems.
 
174
     *
 
175
     * @param l the listener to register (must not be <b>null</b>)
 
176
     * @since 1.4
 
177
     */
 
178
    public void addErrorListener(ConfigurationErrorListener l)
 
179
    {
 
180
        checkListener(l);
 
181
        errorListeners.add(l);
 
182
    }
 
183
 
 
184
    /**
 
185
     * Removes the specified error listener so that it does not receive any
 
186
     * further events caused by this object.
 
187
     *
 
188
     * @param l the listener to remove
 
189
     * @return a flag whether the listener could be found and removed
 
190
     * @since 1.4
 
191
     */
 
192
    public boolean removeErrorListener(ConfigurationErrorListener l)
 
193
    {
 
194
        return errorListeners.remove(l);
 
195
    }
 
196
 
 
197
    /**
 
198
     * Removes all registered error listeners.
 
199
     *
 
200
     * @since 1.4
 
201
     */
 
202
    public void clearErrorListeners()
 
203
    {
 
204
        errorListeners.clear();
 
205
    }
 
206
 
 
207
    /**
 
208
     * Returns a collection with all configuration error listeners that are
 
209
     * currently registered at this object.
 
210
     *
 
211
     * @return a collection with the registered
 
212
     * {@code ConfigurationErrorListener}s (this collection is a
 
213
     * snapshot of the currently registered listeners; it cannot be manipulated)
 
214
     * @since 1.4
 
215
     */
 
216
    public Collection<ConfigurationErrorListener> getErrorListeners()
 
217
    {
 
218
        return Collections.unmodifiableCollection(new ArrayList<ConfigurationErrorListener>(errorListeners));
 
219
    }
 
220
 
 
221
    /**
 
222
     * Creates an event object and delivers it to all registered event
 
223
     * listeners. The method will check first if sending an event is allowed
 
224
     * (making use of the {@code detailEvents} property), and if
 
225
     * listeners are registered.
 
226
     *
 
227
     * @param type the event's type
 
228
     * @param propName the name of the affected property (can be <b>null</b>)
 
229
     * @param propValue the value of the affected property (can be <b>null</b>)
 
230
     * @param before the before update flag
 
231
     */
 
232
    protected void fireEvent(int type, String propName, Object propValue, boolean before)
 
233
    {
 
234
        if (checkDetailEvents(-1))
 
235
        {
 
236
            Iterator<ConfigurationListener> it = listeners.iterator();
 
237
            if (it.hasNext())
 
238
            {
 
239
                ConfigurationEvent event =
 
240
                        createEvent(type, propName, propValue, before);
 
241
                while (it.hasNext())
 
242
                {
 
243
                    it.next().configurationChanged(event);
 
244
                }
 
245
            }
 
246
        }
 
247
    }
 
248
 
 
249
    /**
 
250
     * Creates a {@code ConfigurationEvent} object based on the passed in
 
251
     * parameters. This is called by {@code fireEvent()} if it decides
 
252
     * that an event needs to be generated.
 
253
     *
 
254
     * @param type the event's type
 
255
     * @param propName the name of the affected property (can be <b>null</b>)
 
256
     * @param propValue the value of the affected property (can be <b>null</b>)
 
257
     * @param before the before update flag
 
258
     * @return the newly created event object
 
259
     */
 
260
    protected ConfigurationEvent createEvent(int type, String propName, Object propValue, boolean before)
 
261
    {
 
262
        return new ConfigurationEvent(this, type, propName, propValue, before);
 
263
    }
 
264
 
 
265
    /**
 
266
     * Creates an error event object and delivers it to all registered error
 
267
     * listeners.
 
268
     *
 
269
     * @param type the event's type
 
270
     * @param propName the name of the affected property (can be <b>null</b>)
 
271
     * @param propValue the value of the affected property (can be <b>null</b>)
 
272
     * @param ex the {@code Throwable} object that caused this error event
 
273
     * @since 1.4
 
274
     */
 
275
    protected void fireError(int type, String propName, Object propValue, Throwable ex)
 
276
    {
 
277
        Iterator<ConfigurationErrorListener> it = errorListeners.iterator();
 
278
        if (it.hasNext())
 
279
        {
 
280
            ConfigurationErrorEvent event =
 
281
                    createErrorEvent(type, propName, propValue, ex);
 
282
            while (it.hasNext())
 
283
            {
 
284
                it.next().configurationError(event);
 
285
            }
 
286
        }
 
287
    }
 
288
 
 
289
    /**
 
290
     * Creates a {@code ConfigurationErrorEvent} object based on the
 
291
     * passed in parameters. This is called by {@code fireError()} if it
 
292
     * decides that an event needs to be generated.
 
293
     *
 
294
     * @param type the event's type
 
295
     * @param propName the name of the affected property (can be <b>null</b>)
 
296
     * @param propValue the value of the affected property (can be <b>null</b>)
 
297
     * @param ex the {@code Throwable} object that caused this error
 
298
     * event
 
299
     * @return the event object
 
300
     * @since 1.4
 
301
     */
 
302
    protected ConfigurationErrorEvent createErrorEvent(int type, String propName, Object propValue, Throwable ex)
 
303
    {
 
304
        return new ConfigurationErrorEvent(this, type, propName, propValue, ex);
 
305
    }
 
306
 
 
307
    /**
 
308
     * Overrides the {@code clone()} method to correctly handle so far
 
309
     * registered event listeners. This implementation ensures that the clone
 
310
     * will have empty event listener lists, i.e. the listeners registered at an
 
311
     * {@code EventSource} object will not be copied.
 
312
     *
 
313
     * @return the cloned object
 
314
     * @throws CloneNotSupportedException if cloning is not allowed
 
315
     * @since 1.4
 
316
     */
 
317
    @Override
 
318
    protected Object clone() throws CloneNotSupportedException
 
319
    {
 
320
        EventSource copy = (EventSource) super.clone();
 
321
        copy.initListeners();
 
322
        return copy;
 
323
    }
 
324
 
 
325
    /**
 
326
     * Checks whether the specified event listener is not <b>null</b>. If this
 
327
     * is the case, an {@code IllegalArgumentException} exception is thrown.
 
328
     *
 
329
     * @param l the listener to be checked
 
330
     * @throws IllegalArgumentException if the listener is <b>null</b>
 
331
     */
 
332
    private static void checkListener(Object l)
 
333
    {
 
334
        if (l == null)
 
335
        {
 
336
            throw new IllegalArgumentException("Listener must not be null!");
 
337
        }
 
338
    }
 
339
 
 
340
    /**
 
341
     * Initializes the collections for storing registered event listeners.
 
342
     */
 
343
    private void initListeners()
 
344
    {
 
345
        listeners = new CopyOnWriteArrayList<ConfigurationListener>();
 
346
        errorListeners = new CopyOnWriteArrayList<ConfigurationErrorListener>();
 
347
    }
 
348
 
 
349
    /**
 
350
     * Helper method for checking the current counter for detail events. This
 
351
     * method checks whether the counter is greater than the passed in limit.
 
352
     *
 
353
     * @param limit the limit to be compared to
 
354
     * @return <b>true</b> if the counter is greater than the limit,
 
355
     *         <b>false</b> otherwise
 
356
     */
 
357
    private boolean checkDetailEvents(int limit)
 
358
    {
 
359
        synchronized (lockDetailEventsCount)
 
360
        {
 
361
            return detailEvents > limit;
 
362
        }
 
363
    }
 
364
}