KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > valves > CometConnectionManagerValve


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
18
19 package org.apache.catalina.valves;
20
21
22 import java.io.IOException JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.concurrent.ConcurrentHashMap JavaDoc;
25
26 import javax.servlet.ServletException JavaDoc;
27 import javax.servlet.http.HttpSession JavaDoc;
28 import javax.servlet.http.HttpSessionEvent JavaDoc;
29 import javax.servlet.http.HttpSessionListener JavaDoc;
30
31 import org.apache.catalina.CometEvent;
32 import org.apache.catalina.Context;
33 import org.apache.catalina.Lifecycle;
34 import org.apache.catalina.LifecycleEvent;
35 import org.apache.catalina.LifecycleException;
36 import org.apache.catalina.LifecycleListener;
37 import org.apache.catalina.connector.CometEventImpl;
38 import org.apache.catalina.connector.Request;
39 import org.apache.catalina.connector.Response;
40 import org.apache.catalina.util.LifecycleSupport;
41 import org.apache.catalina.util.StringManager;
42
43
44 /**
45  * <p>Implementation of a Valve that tracks Comet connections, and closes them
46  * when the associated session expires or the webapp is reloaded.</p>
47  *
48  * <p>This Valve should be attached to a Context.</p>
49  *
50  * @author Remy Maucherat
51  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
52  */

53
54 public class CometConnectionManagerValve
55     extends ValveBase
56     implements Lifecycle, HttpSessionListener JavaDoc, LifecycleListener {
57
58
59     // ----------------------------------------------------- Instance Variables
60

61
62     /**
63      * The descriptive information related to this implementation.
64      */

65     protected static final String JavaDoc info =
66         "org.apache.catalina.valves.CometConnectionManagerValve/1.0";
67
68
69     /**
70      * The string manager for this package.
71      */

72     protected StringManager sm =
73         StringManager.getManager(Constants.Package);
74
75
76     /**
77      * The lifecycle event support for this component.
78      */

79     protected LifecycleSupport lifecycle = new LifecycleSupport(this);
80
81
82     /**
83      * Has this component been started yet?
84      */

85     protected boolean started = false;
86
87     
88     /**
89      * Connection list.
90      */

91     protected ConcurrentHashMap JavaDoc<String JavaDoc, ConnectionInfo[]> connections
92         = new ConcurrentHashMap JavaDoc<String JavaDoc, ConnectionInfo[]>();
93     
94
95     // ------------------------------------------------------------- Properties
96

97     
98     // ------------------------------------------------------ Lifecycle Methods
99

100
101     /**
102      * Add a lifecycle event listener to this component.
103      *
104      * @param listener The listener to add
105      */

106     public void addLifecycleListener(LifecycleListener listener) {
107
108         lifecycle.addLifecycleListener(listener);
109
110     }
111
112
113     /**
114      * Get the lifecycle listeners associated with this lifecycle. If this
115      * Lifecycle has no listeners registered, a zero-length array is returned.
116      */

117     public LifecycleListener[] findLifecycleListeners() {
118
119         return lifecycle.findLifecycleListeners();
120
121     }
122
123
124     /**
125      * Remove a lifecycle event listener from this component.
126      *
127      * @param listener The listener to add
128      */

129     public void removeLifecycleListener(LifecycleListener listener) {
130
131         lifecycle.removeLifecycleListener(listener);
132
133     }
134
135
136     /**
137      * Prepare for the beginning of active use of the public methods of this
138      * component. This method should be called after <code>configure()</code>,
139      * and before any of the public methods of the component are utilized.
140      *
141      * @exception LifecycleException if this component detects a fatal error
142      * that prevents this component from being used
143      */

144     public void start() throws LifecycleException {
145
146         // Validate and update our current component state
147
if (started)
148             throw new LifecycleException
149                 (sm.getString("semaphoreValve.alreadyStarted"));
150         lifecycle.fireLifecycleEvent(START_EVENT, null);
151         started = true;
152
153         if (container instanceof Context) {
154             ((Lifecycle) container).addLifecycleListener(this);
155         }
156         
157     }
158
159
160     /**
161      * Gracefully terminate the active use of the public methods of this
162      * component. This method should be the last one called on a given
163      * instance of this component.
164      *
165      * @exception LifecycleException if this component detects a fatal error
166      * that needs to be reported
167      */

168     public void stop() throws LifecycleException {
169
170         // Validate and update our current component state
171
if (!started)
172             throw new LifecycleException
173                 (sm.getString("semaphoreValve.notStarted"));
174         lifecycle.fireLifecycleEvent(STOP_EVENT, null);
175         started = false;
176
177         if (container instanceof Context) {
178             ((Lifecycle) container).removeLifecycleListener(this);
179         }
180
181         // The webapp is getting stopped, so all current connections
182
// should be closed
183
// Close all Comet connections associated with this session
184
// Note: this will only be done if the container was not a Context
185
// (otherwise, this needs to be done before stop, as the servlet would
186
// be deallocated already)
187
Iterator JavaDoc<ConnectionInfo[]> iterator = connections.values().iterator();
188         while (iterator.hasNext()) {
189             ConnectionInfo[] connectionInfos = iterator.next();
190             if (connectionInfos != null) {
191                 for (int i = 0; i < connectionInfos.length; i++) {
192                     ConnectionInfo connectionInfo = connectionInfos[i];
193                     try {
194                         connectionInfo.event.close();
195                     } catch (Exception JavaDoc e) {
196                         container.getLogger().warn(sm.getString("cometConnectionManagerValve.event"), e);
197                     }
198                 }
199             }
200         }
201         connections.clear();
202
203     }
204
205     
206     public void lifecycleEvent(LifecycleEvent event) {
207         if (event.getType() == Lifecycle.BEFORE_STOP_EVENT) {
208             // The webapp is getting stopped, so all current connections
209
// should be closed
210
// Close all Comet connections associated with this session
211
Iterator JavaDoc<ConnectionInfo[]> iterator = connections.values().iterator();
212             while (iterator.hasNext()) {
213                 ConnectionInfo[] connectionInfos = iterator.next();
214                 if (connectionInfos != null) {
215                     for (int i = 0; i < connectionInfos.length; i++) {
216                         ConnectionInfo connectionInfo = connectionInfos[i];
217                         try {
218                             ((CometEventImpl) connectionInfo.event).setEventType(CometEvent.EventType.END);
219                             ((CometEventImpl) connectionInfo.event).setEventSubType(CometEvent.EventSubType.WEBAPP_RELOAD);
220                             getNext().event(connectionInfo.request, connectionInfo.response, connectionInfo.event);
221                             connectionInfo.event.close();
222                         } catch (Exception JavaDoc e) {
223                             container.getLogger().warn(sm.getString("cometConnectionManagerValve.event"), e);
224                         }
225                     }
226                 }
227             }
228             connections.clear();
229         }
230     }
231
232
233     // --------------------------------------------------------- Public Methods
234

235
236     /**
237      * Return descriptive information about this Valve implementation.
238      */

239     public String JavaDoc getInfo() {
240         return (info);
241     }
242
243
244     /**
245      * Register requests for tracking, whenever needed.
246      *
247      * @param request The servlet request to be processed
248      * @param response The servlet response to be created
249      *
250      * @exception IOException if an input/output error occurs
251      * @exception ServletException if a servlet error occurs
252      */

253     public void invoke(Request request, Response response)
254         throws IOException JavaDoc, ServletException JavaDoc {
255         // Perform the request
256
getNext().invoke(request, response);
257         
258         if (request.isComet() && !response.isClosed()) {
259             // Start tracking this connection, since this is a
260
// begin event, and Comet mode is on
261
HttpSession JavaDoc session = request.getSession(true);
262             ConnectionInfo newConnectionInfo = new ConnectionInfo();
263             newConnectionInfo.request = request;
264             newConnectionInfo.response = response;
265             newConnectionInfo.event = request.getEvent();
266             synchronized (session) {
267                 String JavaDoc id = session.getId();
268                 ConnectionInfo[] connectionInfos = connections.get(id);
269                 if (connectionInfos == null) {
270                     connectionInfos = new ConnectionInfo[1];
271                     connectionInfos[0] = newConnectionInfo;
272                     connections.put(id, connectionInfos);
273                 } else {
274                     ConnectionInfo[] newConnectionInfos =
275                         new ConnectionInfo[connectionInfos.length + 1];
276                     for (int i = 0; i < connectionInfos.length; i++) {
277                         newConnectionInfos[i] = connectionInfos[i];
278                     }
279                     newConnectionInfos[connectionInfos.length] = newConnectionInfo;
280                     connections.put(id, newConnectionInfos);
281                 }
282             }
283         }
284         
285     }
286
287     
288     /**
289      * Use events to update the connection state.
290      *
291      * @param request The servlet request to be processed
292      * @param response The servlet response to be created
293      *
294      * @exception IOException if an input/output error occurs
295      * @exception ServletException if a servlet error occurs
296      */

297     public void event(Request request, Response response, CometEvent event)
298         throws IOException JavaDoc, ServletException JavaDoc {
299         
300         // Perform the request
301
boolean ok = false;
302         try {
303             getNext().event(request, response, event);
304             ok = true;
305         } finally {
306             if (!ok || response.isClosed()
307                     || (event.getEventType() == CometEvent.EventType.END)
308                     || (event.getEventType() == CometEvent.EventType.ERROR
309                             && !(event.getEventSubType() == CometEvent.EventSubType.TIMEOUT))) {
310                 // Remove from tracked list, the connection is done
311
HttpSession JavaDoc session = request.getSession(true);
312                 synchronized (session) {
313                     ConnectionInfo[] connectionInfos = connections.get(session.getId());
314                     if (connectionInfos != null) {
315                         boolean found = false;
316                         for (int i = 0; !found && (i < connectionInfos.length); i++) {
317                             found = (connectionInfos[i].request == request);
318                         }
319                         if (found) {
320                             ConnectionInfo[] newConnectionInfos =
321                                 new ConnectionInfo[connectionInfos.length - 1];
322                             int pos = 0;
323                             for (int i = 0; i < connectionInfos.length; i++) {
324                                 if (connectionInfos[i].request != request) {
325                                     newConnectionInfos[pos++] = connectionInfos[i];
326                                 }
327                             }
328                             connections.put(session.getId(), newConnectionInfos);
329                         }
330                     }
331                 }
332             }
333         }
334         
335     }
336
337
338     public void sessionCreated(HttpSessionEvent JavaDoc se) {
339     }
340
341
342     public void sessionDestroyed(HttpSessionEvent JavaDoc se) {
343         // Close all Comet connections associated with this session
344
ConnectionInfo[] connectionInfos = connections.remove(se.getSession().getId());
345         if (connectionInfos != null) {
346             for (int i = 0; i < connectionInfos.length; i++) {
347                 ConnectionInfo connectionInfo = connectionInfos[i];
348                 try {
349                     ((CometEventImpl) connectionInfo.event).setEventType(CometEvent.EventType.END);
350                     ((CometEventImpl) connectionInfo.event).setEventSubType(CometEvent.EventSubType.SESSION_END);
351                     getNext().event(connectionInfo.request, connectionInfo.response, connectionInfo.event);
352                     connectionInfo.event.close();
353                 } catch (Exception JavaDoc e) {
354                     container.getLogger().warn(sm.getString("cometConnectionManagerValve.event"), e);
355                 }
356             }
357         }
358     }
359
360
361     // --------------------------------------------- ConnectionInfo Inner Class
362

363     
364     protected class ConnectionInfo {
365         public CometEvent event;
366         public Request request;
367         public Response response;
368     }
369
370
371 }
372
Popular Tags