KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > blojsom > event > SimpleEventBroadcaster


1 /**
2  * Copyright (c) 2003-2006, David A. Czarnecki
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * Redistributions of source code must retain the above copyright notice, this list of conditions and the
9  * following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
11  * following disclaimer in the documentation and/or other materials provided with the distribution.
12  * Neither the name of "David A. Czarnecki" and "blojsom" nor the names of its contributors may be used to
13  * endorse or promote products derived from this software without specific prior written permission.
14  * Products derived from this software may not be called "blojsom", nor may "blojsom" appear in their name,
15  * without prior written permission of David A. Czarnecki.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21  * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */

31 package org.blojsom.event;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35
36 import java.util.*;
37
38 /**
39  * SimpleEventBroadcaster.
40  * <p></p>
41  * Events are broadcast to each event in a separate thread so that the broadcaster is not a bottleneck.
42  * No defined order is set for how each event will receive an event, so you should not assume any order
43  * in listeners being called. No steps are taken to ensure a event does not receive an event if it is
44  * removed at the same time an event is being broadcast.
45  * <p></p>
46  * The addition of the {@link #processEvent(Event)} method adds the capability for components to have an
47  * event processed after the call instead of asynchronously as with the {@link #broadcastEvent(Event)} method.
48  *
49  * @author David Czarnecki
50  * @version $Id: SimpleEventBroadcaster.java,v 1.1 2006/03/20 21:31:13 czarneckid Exp $
51  * @since blojsom 3.0
52  */

53 public class SimpleEventBroadcaster implements EventBroadcaster {
54
55     private Log _logger = LogFactory.getLog(SimpleEventBroadcaster.class);
56
57     private static Set _listeners;
58     private static Map _listenerToHandler;
59
60     /**
61      * Default constructor.
62      */

63     public SimpleEventBroadcaster() {
64         if (_listeners == null) {
65             _listeners = new HashSet();
66         } else {
67             // @todo Can Spring support a singleton bean across servlets/application contexts?
68
if (_logger.isDebugEnabled()) {
69                 _logger.debug("Using shared listeners map");
70             }
71         }
72
73         if (_listenerToHandler == null) {
74             _listenerToHandler = new HashMap();
75         } else {
76             // @todo Can Spring support a singleton bean across servlets/application contexts?
77
if (_logger.isDebugEnabled()) {
78                 _logger.debug("Using shared listener to handler map");
79             }
80         }
81
82         if (_logger.isDebugEnabled()) {
83             _logger.debug("Initialized simple event broadcaster");
84         }
85     }
86
87     /**
88      * Add a event to this event broadcaster
89      *
90      * @param listener {@link Listener}
91      */

92     public void addListener(Listener listener) {
93         EventHandler handler = new EventHandler(listener, new Filter() {
94             /**
95              * Determines whether or not a particular event should be processed
96              *
97              * @param event {@link Event} to be processed
98              * @return <code>true</code> if the event should be processed, <code>false</code> otherwise
99              */

100             public boolean processEvent(Event event) {
101                 return true;
102             }
103         });
104
105         if (!_listenerToHandler.containsKey(listener.getClass().getName())) {
106             _listeners.add(handler);
107             _listenerToHandler.put(listener.getClass().getName(), handler);
108             if (_logger.isDebugEnabled()) {
109                 _logger.debug("Added event listener: " + listener.getClass().getName() + " with process all events filter");
110             }
111         }
112     }
113
114     /**
115      * Add a event to this event broadcaster. Events are filtered using the {@link org.blojsom.event.Filter} instance
116      * passed to this method.
117      *
118      * @param listener {@link Listener}
119      * @param filter {@link Filter} used to filter events
120      */

121     public void addListener(Listener listener, Filter filter) {
122         EventHandler handler = new EventHandler(listener, filter);
123
124         if (!_listenerToHandler.containsKey(listener.getClass().getName())) {
125             _listeners.add(handler);
126             _listenerToHandler.put(listener.getClass().getName(), handler);
127             if (_logger.isDebugEnabled()) {
128                 _logger.debug("Added event listener: " + listener.getClass().getName() + " with filter: " + filter.getClass().getName());
129             }
130         }
131     }
132
133     /**
134      * Remove a event from this event broadcaster
135      *
136      * @param listener {@link Listener}
137      */

138     public void removeListener(Listener listener) {
139         if (_listenerToHandler.containsKey(listener.getClass().getName())) {
140             EventHandler handler = (EventHandler) _listenerToHandler.get(listener.getClass().getName());
141             _listeners.remove(handler);
142             _listenerToHandler.remove(listener.getClass().getName());
143         }
144
145         if (_logger.isDebugEnabled()) {
146             _logger.debug("Removed event listener: " + listener.getClass().getName());
147         }
148     }
149
150     /**
151      * Broadcast an event to all listeners
152      *
153      * @param event {@link Event} to be broadcast to all listeners
154      */

155     public void broadcastEvent(Event event) {
156         Thread JavaDoc eventBroadcaster = new Thread JavaDoc(new AsynchronousEventBroadcaster(event));
157         eventBroadcaster.setDaemon(true);
158         eventBroadcaster.start();
159     }
160
161     /**
162      * Process an event with all listeners
163      *
164      * @param event {@link Event} to be processed by all listeners
165      */

166     public void processEvent(Event event) {
167         Iterator handlerIterator = _listeners.iterator();
168         while (handlerIterator.hasNext()) {
169             EventHandler eventHandler = (EventHandler) handlerIterator.next();
170             if (eventHandler._filter.processEvent(event)) {
171                 eventHandler._listener.processEvent(event);
172             }
173         }
174     }
175
176     /**
177      * Event handler helper class.
178      */

179     protected class EventHandler {
180
181         protected Listener _listener;
182         protected Filter _filter;
183
184         /**
185          * Create a new event handler with event and filter instances.
186          *
187          * @param listener {@link Listener}
188          * @param filter {@link Filter}
189          */

190         protected EventHandler(Listener listener, Filter filter) {
191             _listener = listener;
192             _filter = filter;
193         }
194     }
195
196     /**
197      * Thread to handle broadcasting an event to registered listeners.
198      */

199     private class AsynchronousEventBroadcaster implements Runnable JavaDoc {
200
201         private Event _event;
202
203         public AsynchronousEventBroadcaster(Event event) {
204             _event = event;
205         }
206
207         /**
208          * Iterates over the set of {@link EventHandler} registered with this broadcaster and calls
209          * the {@link Listener#handleEvent(Event)} method with the
210          * {@link Event}.
211          */

212         public void run() {
213             Iterator handlerIterator = _listeners.iterator();
214             while (handlerIterator.hasNext()) {
215                 EventHandler eventHandler = (EventHandler) handlerIterator.next();
216                 if (eventHandler._filter.processEvent(_event)) {
217                     eventHandler._listener.handleEvent(_event);
218                 }
219             }
220         }
221     }
222 }
Popular Tags