1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.LinkedList;
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 machanism. In this case these
33 * classes only need to call the <code>fireEvent()</code> 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</code> 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()</code> method that can be implemented as a
45 * combination of <code>clearProperty()</code> and <code>addProperty()</code>.
46 * With <code>detailEvents</code> 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 * <code>{@link org.apache.commons.configuration.HierarchicalConfiguration HierarchicalConfiguration}</code>
53 * for instance has a custom implementation of <code>setProperty()</code>, which
54 * does not generate any detail events.
55 * </p>
56 *
57 * @author <a
58 * href="http://jakarta.apache.org/commons/configuration/team-list.html">Commons
59 * Configuration team</a>
60 * @version $Id: EventSource.java 439648 2006-09-02 20:42:10Z oheger $
61 * @since 1.3
62 */
63 public class EventSource
64 {
65 /*** A collection for the registered event listeners. */
66 private Collection listeners;
67
68 /*** A counter for the detail events. */
69 private int detailEvents;
70
71 /***
72 * Creates a new instance of <code>EventSource</code>.
73 */
74 public EventSource()
75 {
76 clearConfigurationListeners();
77 }
78
79 /***
80 * Adds a configuration listener to this object.
81 *
82 * @param l the listener to add
83 */
84 public void addConfigurationListener(ConfigurationListener l)
85 {
86 if (l == null)
87 {
88 throw new IllegalArgumentException("Listener must not be null!");
89 }
90 synchronized (listeners)
91 {
92 listeners.add(l);
93 }
94 }
95
96 /***
97 * Removes the specified event listener so that it does not receive any
98 * further events caused by this object.
99 *
100 * @param l the listener to be removed
101 * @return a flag whether the event listener was found
102 */
103 public boolean removeConfigurationListener(ConfigurationListener l)
104 {
105 synchronized (listeners)
106 {
107 return listeners.remove(l);
108 }
109 }
110
111 /***
112 * Returns a collection with all configuration event listeners that are
113 * currently registered at this object.
114 *
115 * @return a collection with the registered
116 * <code>ConfigurationListener</code>s (this collection cannot be
117 * changed)
118 */
119 public Collection getConfigurationListeners()
120 {
121 synchronized (listeners)
122 {
123 return Collections.unmodifiableCollection(listeners);
124 }
125 }
126
127 /***
128 * Removes all registered configuration listeners.
129 */
130 public void clearConfigurationListeners()
131 {
132 listeners = new LinkedList();
133 }
134
135 /***
136 * Returns a flag whether detail events are enabled.
137 *
138 * @return a flag if detail events are generated
139 */
140 public boolean isDetailEvents()
141 {
142 synchronized (listeners)
143 {
144 return detailEvents > 0;
145 }
146 }
147
148 /***
149 * Determines whether detail events should be generated. If enabled, some
150 * methods can generate multiple update events. Note that this method
151 * records the number of calls, i.e. if for instance
152 * <code>setDetailEvents(false)</code> was called three times, you will
153 * have to invoke the method as often to enable the details.
154 *
155 * @param enable a flag if detail events should be enabled or disabled
156 */
157 public void setDetailEvents(boolean enable)
158 {
159 synchronized (listeners)
160 {
161 if (enable)
162 {
163 detailEvents++;
164 }
165 else
166 {
167 detailEvents--;
168 }
169 }
170 }
171
172 /***
173 * Creates an event object and delivers it to all registered event
174 * listeners. The method will check first if sending an event is allowed
175 * (making use of the <code>detailEvents</code> property), and if
176 * listeners are registered.
177 *
178 * @param type the event's type
179 * @param propName the name of the affected property (can be <b>null</b>)
180 * @param propValue the value of the affected property (can be <b>null</b>)
181 * @param before the before update flag
182 */
183 protected void fireEvent(int type, String propName, Object propValue,
184 boolean before)
185 {
186 Collection listenersToCall = null;
187
188 synchronized (listeners)
189 {
190 if (detailEvents >= 0 && listeners.size() > 0)
191 {
192
193
194 listenersToCall = new ArrayList(listeners);
195 }
196 }
197
198 if (listenersToCall != null)
199 {
200 ConfigurationEvent event = createEvent(type, propName, propValue,
201 before);
202 for (Iterator it = listenersToCall.iterator(); it.hasNext();)
203 {
204 ((ConfigurationListener) it.next()).configurationChanged(event);
205 }
206 }
207 }
208
209 /***
210 * Creates a <code>ConfigurationEvent</code> object based on the passed in
211 * parameters. This is called by <code>fireEvent()</code> if it decides
212 * that an event needs to be generated.
213 *
214 * @param type the event's type
215 * @param propName the name of the affected property (can be <b>null</b>)
216 * @param propValue the value of the affected property (can be <b>null</b>)
217 * @param before the before update flag
218 * @return the newly created event object
219 */
220 protected ConfigurationEvent createEvent(int type, String propName,
221 Object propValue, boolean before)
222 {
223 return new ConfigurationEvent(this, type, propName, propValue, before);
224 }
225 }