KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > handlers > SimpleSessionHandler


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.axis.handlers;
18
19 import org.apache.axis.AxisEngine;
20 import org.apache.axis.AxisFault;
21 import org.apache.axis.Constants;
22 import org.apache.axis.Message;
23 import org.apache.axis.MessageContext;
24 import org.apache.axis.components.logger.LogFactory;
25 import org.apache.axis.message.SOAPEnvelope;
26 import org.apache.axis.message.SOAPHeaderElement;
27 import org.apache.axis.session.SimpleSession;
28 import org.apache.axis.utils.Messages;
29 import org.apache.axis.utils.SessionUtils;
30 import org.apache.commons.logging.Log;
31
32 import javax.xml.namespace.QName JavaDoc;
33 import javax.xml.rpc.server.ServiceLifecycle JavaDoc;
34 import java.util.Enumeration JavaDoc;
35 import java.util.HashSet JavaDoc;
36 import java.util.Hashtable JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.Map JavaDoc;
39 import java.util.Set JavaDoc;
40
41 /** This handler uses SOAP headers to do simple session management.
42  *
43  * <p>Essentially, you install it on both the request and response chains of
44  * your service, on both the client and the server side.</p>
45  *
46  * <p>ON THE SERVER:</p>
47  * <ul>
48  * <li>The REQUEST is checked for a session ID header. If present, we
49  * look up the correct SimpleSession. If not, we create a new session.
50  * In either case, we install the session into the MessageContext, and
51  * put its ID in the SESSION_ID property.
52  * <li>The RESPONSE gets a session ID header tacked on, assuming we found a
53  * SESSION_ID property in the MessageContext.
54  * </ul>
55  * <p>ON THE CLIENT:</p>
56  * <ul>
57  * <li>The RESPONSE messages are checked for session ID headers. If present,
58  * we pull the ID out and insert it into an option in the AxisClient.
59  * This works because a given Call object is associated with a single
60  * AxisClient. However, we might want to find a way to put it into the
61  * Call object itself, which would make a little more sense. This would
62  * mean being able to get to the Call from the MC, i.e. adding a getCall()
63  * API (which would only work on the client side)....
64  * <li>When REQUESTS are generated, we look to see if an ID option is present
65  * in the AxisClient associated with the MessageContext. If so, we
66  * insert a session ID header with the appropriate ID.
67  * </ul>
68  *
69  * <p>SimpleSessions are "reaped" periodically via a very simplistic
70  * mechanism. Each time the handler is invoke()d we check to see if more
71  * than <b>reapPeriodicity</b> milliseconds have elapsed since the last
72  * reap. If so, we walk the collection of active Sessions, and for each
73  * one, if it hasn't been "touched" (i.e. had a getProperty() or setProperty()
74  * performed) in longer than its timeout, we remove it from the collection.</p>
75  *
76  * @author Glen Daniels (gdaniels@apache.org)
77  */

78 public class SimpleSessionHandler extends BasicHandler
79 {
80     protected static Log log =
81         LogFactory.getLog(SimpleSessionHandler.class.getName());
82
83     public static final String JavaDoc SESSION_ID = "SimpleSession.id";
84     public static final String JavaDoc SESSION_NS = "http://xml.apache.org/axis/session";
85     public static final String JavaDoc SESSION_LOCALPART = "sessionID";
86     public static final QName JavaDoc sessionHeaderName = new QName JavaDoc(SESSION_NS,
87                                                             SESSION_LOCALPART);
88
89     private Hashtable JavaDoc activeSessions = new Hashtable JavaDoc();
90
91     // Reap timed-out sessions on the first request after this many
92
// seconds.
93
private long reapPeriodicity = 30;
94     private long lastReapTime = 0;
95
96     // By default, sessions time out after 1 minute of inactivity (60 sec)
97
private int defaultSessionTimeout = 60;
98
99     /**
100      * Process a MessageContext.
101      */

102     public void invoke(MessageContext context) throws AxisFault
103     {
104         // Should we reap timed out sessions?
105
long curTime = System.currentTimeMillis();
106         boolean reap = false;
107         
108         // Minimize synchronicity, just check in here, do reap later.
109
synchronized (this) {
110             if (curTime > lastReapTime + (reapPeriodicity * 1000)) {
111                 reap = true;
112                 lastReapTime = curTime;
113             }
114         }
115         
116         if (reap) {
117             Set JavaDoc entries = activeSessions.entrySet();
118             Set JavaDoc victims = new HashSet JavaDoc();
119             Object JavaDoc key;
120             Iterator JavaDoc i;
121             for (i = entries.iterator(); i.hasNext();) {
122                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
123                 key = entry.getKey();
124                 SimpleSession session = (SimpleSession) entry.getValue();
125                 if ((curTime - session.getLastAccessTime()) >
126                      (session.getTimeout() * 1000)) {
127                     log.debug(Messages.getMessage("timeout00",
128                                                         key.toString()));
129
130                     // Don't modify the hashtable while we're iterating.
131
victims.add(key);
132                 }
133             }
134
135             // Now go remove all the victims we found during the iteration.
136
for (i = victims.iterator(); i.hasNext();) {
137                 key = i.next();
138                 SimpleSession session = (SimpleSession)activeSessions.get(key);
139                 activeSessions.remove(key);
140
141                 // For each victim, swing through the data looking for
142
// ServiceLifecycle objects, and calling destroy() on them.
143
// FIXME : This cleanup should probably happen on another
144
// thread, as it might take a little while.
145
Enumeration JavaDoc keys = session.getKeys();
146                 while (keys != null && keys.hasMoreElements()) {
147                     String JavaDoc keystr = (String JavaDoc)keys.nextElement();
148                     Object JavaDoc obj = session.get(keystr);
149                     if (obj != null && obj instanceof ServiceLifecycle JavaDoc) {
150                         ((ServiceLifecycle JavaDoc)obj).destroy();
151                     }
152                 }
153             }
154         }
155         
156         if (context.isClient()) {
157             doClient(context);
158         } else {
159             doServer(context);
160         }
161     }
162
163     /**
164      * Client side of processing.
165      */

166     public void doClient(MessageContext context) throws AxisFault
167     {
168         if (context.getPastPivot()) {
169             // This is a response. Check it for the session header.
170
Message msg = context.getResponseMessage();
171             if (msg == null)
172                 return;
173             SOAPEnvelope env = msg.getSOAPEnvelope();
174             SOAPHeaderElement header = env.getHeaderByName(SESSION_NS,
175                                                            SESSION_LOCALPART);
176             if (header == null)
177                 return;
178             
179             // Got one!
180
try {
181                 Long JavaDoc id = (Long JavaDoc)header.
182                              getValueAsType(Constants.XSD_LONG);
183                 // Store it away.
184
AxisEngine engine = context.getAxisEngine();
185                 engine.setOption(SESSION_ID, id);
186                 // Note that we processed this header!
187
header.setProcessed(true);
188             } catch (Exception JavaDoc e) {
189                 throw AxisFault.makeFault(e);
190             }
191         } else {
192             AxisEngine engine = context.getAxisEngine();
193             Long JavaDoc id = (Long JavaDoc)engine.getOption(SESSION_ID);
194             if (id == null)
195                 return;
196             
197             // We have a session ID, so insert the header
198
Message msg = context.getRequestMessage();
199             if (msg == null)
200                 throw new AxisFault(Messages.getMessage("noRequest00"));
201             
202             SOAPEnvelope env = msg.getSOAPEnvelope();
203             SOAPHeaderElement header = new SOAPHeaderElement(SESSION_NS,
204                                                              SESSION_LOCALPART,
205                                                              id);
206             env.addHeader(header);
207         }
208     }
209
210     /**
211      * Server side of processing.
212      */

213     public void doServer(MessageContext context) throws AxisFault
214     {
215         if (context.getPastPivot()) {
216             // This is a response. Add the session header if we have an
217
// ID.
218
Long JavaDoc id = (Long JavaDoc)context.getProperty(SESSION_ID);
219             if (id == null)
220                 return;
221             
222             Message msg = context.getResponseMessage();
223             if (msg == null)
224                 return;
225             SOAPEnvelope env = msg.getSOAPEnvelope();
226             SOAPHeaderElement header = new SOAPHeaderElement(SESSION_NS,
227                                                              SESSION_LOCALPART,
228                                                              id);
229             env.addHeader(header);
230         } else {
231             // Request. Set up the session if we find the header.
232
Message msg = context.getRequestMessage();
233             if (msg == null)
234                 throw new AxisFault(Messages.getMessage("noRequest00"));
235             
236             SOAPEnvelope env = msg.getSOAPEnvelope();
237             SOAPHeaderElement header = env.getHeaderByName(SESSION_NS,
238                                                            SESSION_LOCALPART);
239             Long JavaDoc id;
240             
241             if (header != null) {
242                 // Got one!
243
try {
244                     id = (Long JavaDoc)header.
245                             getValueAsType(Constants.XSD_LONG);
246                 } catch (Exception JavaDoc e) {
247                     throw AxisFault.makeFault(e);
248                 }
249             } else {
250                 id = getNewSession();
251             }
252             
253             SimpleSession session = (SimpleSession)activeSessions.get(id);
254             if (session == null) {
255                 // Must have timed out, get a new one.
256
id = getNewSession();
257                 session = (SimpleSession)activeSessions.get(id);
258             }
259
260             // This session is still active...
261
session.touch();
262             
263             // Store it away in the MessageContext.
264
context.setSession(session);
265             context.setProperty(SESSION_ID, id);
266         }
267     }
268     
269     /**
270      * Generate a new session, register it, and return its ID.
271      *
272      * @return the new session's ID for later lookup.
273      */

274     private synchronized Long JavaDoc getNewSession()
275     {
276         Long JavaDoc id = SessionUtils.generateSession();
277         SimpleSession session = new SimpleSession();
278         session.setTimeout(defaultSessionTimeout);
279         activeSessions.put(id, session);
280         return id;
281     }
282
283     /**
284      * Set the reaper periodicity in SECONDS
285      *
286      * Convenience method for testing.
287      *
288      * !!! TODO: Should be able to set this via options on the Handler
289      * or perhaps the engine.
290      */

291     public void setReapPeriodicity(long reapTime)
292     {
293         reapPeriodicity = reapTime;
294     }
295
296     /**
297      * Set the default session timeout in SECONDS
298      *
299      * Again, for testing.
300      */

301     public void setDefaultSessionTimeout(int defaultSessionTimeout) {
302         this.defaultSessionTimeout = defaultSessionTimeout;
303     }
304 }
305
Popular Tags