KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icesoft > faces > util > event > servlet > ContextEventRepeater


1 /*
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * "The contents of this file are subject to the Mozilla Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
11  * License for the specific language governing rights and limitations under
12  * the License.
13  *
14  * The Original Code is ICEfaces 1.5 open source software code, released
15  * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
16  * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
17  * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
18  *
19  * Contributor(s): _____________________.
20  *
21  * Alternatively, the contents of this file may be used under the terms of
22  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
23  * License), in which case the provisions of the LGPL License are
24  * applicable instead of those above. If you wish to allow use of your
25  * version of this file only under the terms of the LGPL License and not to
26  * allow others to use your version of this file under the MPL, indicate
27  * your decision by deleting the provisions above and replace them with
28  * the notice and other provisions required by the LGPL License. If you do
29  * not delete the provisions above, a recipient may use your version of
30  * this file under either the MPL or the LGPL License."
31  *
32  */

33
34 package com.icesoft.faces.util.event.servlet;
35
36 import com.icesoft.faces.webapp.http.servlet.SessionDispatcher;
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39
40 import javax.servlet.ServletContext JavaDoc;
41 import javax.servlet.ServletContextEvent JavaDoc;
42 import javax.servlet.ServletContextListener JavaDoc;
43 import javax.servlet.http.HttpSession JavaDoc;
44 import javax.servlet.http.HttpSessionEvent JavaDoc;
45 import javax.servlet.http.HttpSessionListener JavaDoc;
46 import java.util.HashMap JavaDoc;
47 import java.util.Iterator JavaDoc;
48 import java.util.Map JavaDoc;
49 import java.util.Set JavaDoc;
50 import java.util.WeakHashMap JavaDoc;
51
52 /*
53  * The ContextEventRepeater was designed to forward servlet events to different
54  * parts of the ICEfaces framework. These events are typically of interest for
55  * gracefully and/or proactively keeping track of valid sessions and allowing
56  * for orderly shut down.
57  *
58  * This was deemed necessary since the Servlet specification does not allow a
59  * programmatic way of adding and removing listeners for these events. So rather
60  * than have the various ICEfaces pieces register listeners individually, we can
61  * register this class and then add and remove listeners as required.
62  *
63  * The implementation is currently simple and broad. The class maintains a
64  * static collection of listeners in a WeakHashMap and forwards all events to
65  * all registered listeners.
66  *
67  * Future improvements might include:
68  * - adapter implementations
69  * - event filtering
70  *
71  * For now, anything that is interested in receiving events from the repeater
72  * should simply implement the ContextEventListener interface and then add
73  * itself to the ContextEventRepeater using the static addListener method.
74  *
75  * The limitation of adding a listener programmatically is that certain creation
76  * events can occur before the class has a chance to add itself as a listener.
77  * To mitigate this, the ContextEventRepeater buffers the creation events
78  * temporarily. When a ContextEventListener is added, the receiveBufferedEvents
79  * method is called and, if it returns true, any buffered creation events are
80  * sent to the listener after it has been added to the listener collection. The
81  * timing of the events is off but the session information can still be useful.
82  * Events are removed from the buffer when the corresponding destroy events are
83  * received. This means that that sessions that have already been created AND
84  * destroyed are NOT in the buffer.
85  */

86
87 /**
88  *
89  */

90 public class ContextEventRepeater
91         implements HttpSessionListener JavaDoc, ServletContextListener JavaDoc {
92     //todo: fix it... this is just a temporary solution
93
private static SessionDispatcher.Listener SessionDispatcherListener;
94     static {
95         SessionDispatcherListener = new SessionDispatcher.Listener();
96     }
97
98     private static final String JavaDoc ASYNC_SERVER_KEY =
99         "com.icesoft.faces.async.server";
100     private static final String JavaDoc MESSAGING_CONTEXT_EVENT_PUBLISHER_CLASS_NAME =
101         "com.icesoft.faces.util.event.servlet.MessagingContextEventPublisher";
102
103     private static Log log = LogFactory.getLog(ContextEventRepeater.class);
104
105     private static Map JavaDoc bufferedContextEvents = new HashMap JavaDoc();
106     private static ContextEventPublisher contextEventPublisher;
107     private static Map JavaDoc listeners = new WeakHashMap JavaDoc();
108
109     /**
110      * Adds the specified <code>listener</code> to this
111      * <code>ContextEventRepeater</code>. </p>
112      *
113      * @param listener the listener to be added.
114      */

115     public synchronized static void addListener(ContextEventListener listener) {
116         if (listener == null || listeners.containsKey(listener)) {
117             return;
118         }
119         listeners.put(listener, null);
120         if (listener.receiveBufferedEvents()) {
121             sendBufferedEvents(listener);
122         }
123     }
124
125     /**
126      * Fires a new <code>ContextDestroyedEvent</code>, based on the received
127      * <code>event</code>, to all registered listeners, and cleans itself
128      * up. </p>
129      *
130      * @param event the servlet context event.
131      */

132     public synchronized void contextDestroyed(ServletContextEvent JavaDoc event) {
133         SessionDispatcherListener.contextDestroyed(event);
134
135         ContextDestroyedEvent contextDestroyedEvent =
136                 new ContextDestroyedEvent(event);
137         Iterator JavaDoc it = listeners.keySet().iterator();
138         while (it.hasNext()) {
139             ((ContextEventListener) it.next()).
140                     contextDestroyed(contextDestroyedEvent);
141         }
142         listeners.clear();
143         bufferedContextEvents.clear();
144         if (contextEventPublisher != null) {
145             contextEventPublisher.publish(contextDestroyedEvent);
146         }
147         if (log.isInfoEnabled()) {
148             ServletContext JavaDoc servletContext =
149                     contextDestroyedEvent.getServletContext();
150             log.info(
151                 "Servlet Context Name: " +
152                     servletContext.getServletContextName() + ", " +
153                 "Server Info: " + servletContext.getServerInfo());
154         }
155     }
156
157     public synchronized void contextInitialized(ServletContextEvent JavaDoc event) {
158         SessionDispatcherListener.contextInitialized(event);
159
160         boolean _asyncServer;
161         String JavaDoc _asyncServerValue =
162                 event.getServletContext().getInitParameter(ASYNC_SERVER_KEY);
163         if (_asyncServerValue != null) {
164             _asyncServer = Boolean.valueOf(_asyncServerValue).booleanValue();
165         } else {
166             _asyncServer = false;
167             if (log.isDebugEnabled()) {
168                 log.debug("com.icesoft.faces.async.server not defined.");
169             }
170         }
171         if (_asyncServer) {
172             try {
173                 contextEventPublisher =
174                         (ContextEventPublisher)
175                                 Class.forName(
176                                         MESSAGING_CONTEXT_EVENT_PUBLISHER_CLASS_NAME)
177                                         .
178                                                 newInstance();
179                 contextEventPublisher.setContextEventRepeater(this);
180                 contextEventPublisher.publish(
181                         new ContextInitializedEvent(event));
182             } catch (ClassNotFoundException JavaDoc exception) {
183                 if (log.isDebugEnabled()) {
184                     log.debug("MessagingContextEventPublisher is not found!");
185                 }
186             } catch (IllegalAccessException JavaDoc exception) {
187                 if (log.isFatalEnabled()) {
188                     log.fatal(
189                             "Failed to access constructor of " +
190                             "MessagingContextEventPublisher!",
191                             exception);
192                 }
193             } catch (InstantiationException JavaDoc exception) {
194                 if (log.isFatalEnabled()) {
195                     log.fatal(
196                             "Failed to " +
197                             "instantiate MessagingContextEventPublisher!",
198                             exception);
199                 }
200             }
201         }
202     }
203
204     public synchronized static void iceFacesIdDisposed(
205         HttpSession JavaDoc source, String JavaDoc iceFacesId) {
206
207         ICEfacesIDDisposedEvent iceFacesIdDisposedEvent =
208             new ICEfacesIDDisposedEvent(source, iceFacesId);
209         bufferedContextEvents.put(iceFacesIdDisposedEvent, source);
210         Iterator JavaDoc _listeners = listeners.keySet().iterator();
211         while (_listeners.hasNext()) {
212             ((ContextEventListener)_listeners.next()).
213                 iceFacesIdDisposed(iceFacesIdDisposedEvent);
214         }
215         if (contextEventPublisher != null) {
216             contextEventPublisher.publish(iceFacesIdDisposedEvent);
217         }
218         if (log.isTraceEnabled()) {
219             log.trace(
220                 "ICEfaces ID disposed: " +
221                     iceFacesIdDisposedEvent.getICEfacesID());
222         }
223     }
224
225     /**
226      * Fires a new <code>ICEfacesIDRetrievedEvent</code>, with the specified
227      * <code>source</code> and </code>iceFacesId</code>, to all registered
228      * listeners. </p>
229      *
230      * @param source the source of the event.
231      * @param iceFacesId the ICEfaces ID.
232      */

233     public synchronized static void iceFacesIdRetrieved(
234         HttpSession JavaDoc source, String JavaDoc iceFacesId) {
235
236         ICEfacesIDRetrievedEvent iceFacesIdRetrievedEvent =
237             new ICEfacesIDRetrievedEvent(source, iceFacesId);
238         bufferedContextEvents.put(iceFacesIdRetrievedEvent, source);
239         Iterator JavaDoc _listeners = listeners.keySet().iterator();
240         while (_listeners.hasNext()) {
241             ((ContextEventListener) _listeners.next()).
242                 iceFacesIdRetrieved(iceFacesIdRetrievedEvent);
243         }
244         if (contextEventPublisher != null) {
245             contextEventPublisher.publish(iceFacesIdRetrievedEvent);
246         }
247         if (log.isTraceEnabled()) {
248             log.trace(
249                 "ICEfaces ID retrieved: " +
250                     iceFacesIdRetrievedEvent.getICEfacesID());
251         }
252     }
253
254     /**
255      * Removes the specified <code>listener</code> from this
256      * <code>ContextEventRepeater</code>. </p>
257      *
258      * @param listener the listener to be removed.
259      */

260     public synchronized static void removeListener(
261             ContextEventListener listener) {
262
263         if (listener == null) {
264             return;
265         }
266         listeners.remove(listener);
267     }
268
269     public synchronized void sessionCreated(HttpSessionEvent JavaDoc event) {
270         SessionDispatcherListener.sessionCreated(event);
271     }
272
273     /**
274      * Fires a new <code>SessionDestroyedEvent</code>, based on the received
275      * <code>event</code>, to all registered listeners. </p>
276      *
277      * @param event the HTTP session event.
278      */

279     public synchronized void sessionDestroyed(HttpSessionEvent JavaDoc event) {
280         SessionDispatcherListener.sessionDestroyed(event);
281         //It's possible to have a valid session that does not contain an
282
//icefacesID. We should not bail out completely. Simply log a message
283
//and return quietly, but do not broadcast this to the listeners. We
284
//may have to change this behaviour in the future if this becomes a more
285
//general purpose utility.
286
String JavaDoc icefacesID = (String JavaDoc) ((HttpSession JavaDoc) event.getSource())
287                 .getAttribute("icefacesID");
288         if (icefacesID == null || icefacesID.trim().length() < 1) {
289             if (log.isDebugEnabled()) {
290                 log.debug("session does not contain and icefacesID");
291             }
292             return;
293         }
294
295         SessionDestroyedEvent sessionDestroyedEvent =
296                 new SessionDestroyedEvent(event, icefacesID);
297
298         Iterator JavaDoc _listeners = listeners.keySet().iterator();
299         while (_listeners.hasNext()) {
300             ((ContextEventListener) _listeners.next()).
301                     sessionDestroyed(sessionDestroyedEvent);
302         }
303
304         removeBufferedEvents(event.getSession());
305
306         if (contextEventPublisher != null) {
307             contextEventPublisher.publish(sessionDestroyedEvent);
308         }
309         if (log.isTraceEnabled()) {
310             log.trace("ICEfaces ID: " + sessionDestroyedEvent.getICEfacesID());
311         }
312     }
313
314     /**
315      * Fires a new <code>ViewNumberRetrievedEvent</code>, with the specified
316      * <code>source</code> and </code>viewNumber</code>, to all registered
317      * listeners. </p>
318      *
319      * @param source the source of the event.
320      * @param viewNumber the view number.
321      */

322     public synchronized static void viewNumberRetrieved(
323             HttpSession JavaDoc source, String JavaDoc icefacesID, int viewNumber) {
324
325         ViewNumberRetrievedEvent viewNumberRetrievedEvent =
326                 new ViewNumberRetrievedEvent(
327                         source, icefacesID,
328                         viewNumber);
329
330         bufferedContextEvents.put(viewNumberRetrievedEvent, source);
331
332         Iterator JavaDoc _listeners = listeners.keySet().iterator();
333         while (_listeners.hasNext()) {
334             ((ContextEventListener) _listeners.next()).
335                     viewNumberRetrieved(viewNumberRetrievedEvent);
336         }
337         if (contextEventPublisher != null) {
338             contextEventPublisher.publish(viewNumberRetrievedEvent);
339         }
340         if (log.isTraceEnabled()) {
341             log.trace(
342                     "View Number: " + viewNumberRetrievedEvent.getViewNumber());
343         }
344     }
345
346     ContextEvent[] getBufferedContextEvents() {
347         Set JavaDoc _contextEventSet = bufferedContextEvents.keySet();
348         return
349                 (ContextEvent[])
350                         _contextEventSet.toArray(
351                                 new ContextEvent[_contextEventSet.size()]);
352     }
353
354     private synchronized static void removeBufferedEvents(HttpSession JavaDoc session) {
355         Iterator JavaDoc it = bufferedContextEvents.keySet().iterator();
356         Object JavaDoc event = null;
357         HttpSession JavaDoc bufferedSession = null;
358         while (it.hasNext()) {
359             event = it.next();
360             bufferedSession = (HttpSession JavaDoc) bufferedContextEvents.get(event);
361             if (bufferedSession.equals(session)) {
362                 //bufferedContextEvents.remove(event);
363
it.remove();
364             }
365         }
366     }
367
368     private synchronized static void sendBufferedEvents(
369             ContextEventListener listener) {
370
371         Iterator JavaDoc it = bufferedContextEvents.keySet().iterator();
372         while (it.hasNext()) {
373             Object JavaDoc event = it.next();
374             if (event instanceof ICEfacesIDRetrievedEvent) {
375                 listener.iceFacesIdRetrieved(
376                         (ICEfacesIDRetrievedEvent) event);
377             } else if (event instanceof ViewNumberRetrievedEvent) {
378                 listener.viewNumberRetrieved(
379                         (ViewNumberRetrievedEvent) event);
380             }
381         }
382     }
383 }
384
Popular Tags