KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Axis" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55
56 package org.jboss.axis.handlers;
57
58 import org.jboss.axis.AxisEngine;
59 import org.jboss.axis.AxisFault;
60 import org.jboss.axis.Constants;
61 import org.jboss.axis.Message;
62 import org.jboss.axis.MessageContext;
63 import org.jboss.axis.message.SOAPEnvelopeAxisImpl;
64 import org.jboss.axis.message.SOAPHeaderElementAxisImpl;
65 import org.jboss.axis.session.SimpleSession;
66 import org.jboss.axis.utils.Messages;
67 import org.jboss.axis.utils.SessionUtils;
68 import org.jboss.logging.Logger;
69
70 import javax.xml.namespace.QName JavaDoc;
71 import javax.xml.rpc.server.ServiceLifecycle JavaDoc;
72 import java.util.Enumeration JavaDoc;
73 import java.util.HashSet JavaDoc;
74 import java.util.Hashtable JavaDoc;
75 import java.util.Iterator JavaDoc;
76 import java.util.Map JavaDoc;
77 import java.util.Set JavaDoc;
78
79 /**
80  * This handler uses SOAP headers to do simple session management.
81  * <p/>
82  * <p>Essentially, you install it on both the request and response chains of
83  * your service, on both the client and the server side.</p>
84  * <p/>
85  * <p>ON THE SERVER:</p>
86  * <ul>
87  * <li>The REQUEST is checked for a session ID header. If present, we
88  * look up the correct SimpleSession. If not, we create a new session.
89  * In either case, we install the session into the MessageContext, and
90  * put its ID in the SESSION_ID property.
91  * <li>The RESPONSE gets a session ID header tacked on, assuming we found a
92  * SESSION_ID property in the MessageContext.
93  * </ul>
94  * <p>ON THE CLIENT:</p>
95  * <ul>
96  * <li>The RESPONSE messages are checked for session ID headers. If present,
97  * we pull the ID out and insert it into an option in the AxisClient.
98  * This works because a given Call object is associated with a single
99  * AxisClient. However, we might want to find a way to put it into the
100  * Call object itself, which would make a little more sense. This would
101  * mean being able to get to the Call from the MC, i.e. adding a getCall()
102  * API (which would only work on the client side)....
103  * <li>When REQUESTS are generated, we look to see if an ID option is present
104  * in the AxisClient associated with the MessageContext. If so, we
105  * insert a session ID header with the appropriate ID.
106  * </ul>
107  * <p/>
108  * <p>SimpleSessions are "reaped" periodically via a very simplistic
109  * mechanism. Each time the handler is invoke()d we check to see if more
110  * than <b>reapPeriodicity</b> milliseconds have elapsed since the last
111  * reap. If so, we walk the collection of active Sessions, and for each
112  * one, if it hasn't been "touched" (i.e. had a getProperty() or setProperty()
113  * performed) in longer than its timeout, we remove it from the collection.</p>
114  *
115  * @author Glen Daniels (gdaniels@macromedia.com)
116  */

117 public class SimpleSessionHandler extends BasicHandler
118 {
119    private static Logger log = Logger.getLogger(SimpleSessionHandler.class.getName());
120
121    public static final String JavaDoc SESSION_ID = "SimpleSession.id";
122    public static final String JavaDoc SESSION_NS = "http://xml.apache.org/axis/session";
123    public static final String JavaDoc SESSION_LOCALPART = "sessionID";
124    public static final QName JavaDoc sessionHeaderName = new QName JavaDoc(SESSION_NS,
125            SESSION_LOCALPART);
126
127    private Hashtable JavaDoc activeSessions = new Hashtable JavaDoc();
128
129    // Reap timed-out sessions on the first request after this many
130
// seconds.
131
private long reapPeriodicity = 30;
132    private long lastReapTime = 0;
133
134    // By default, sessions time out after 1 minute of inactivity (60 sec)
135
private int defaultSessionTimeout = 60;
136
137    /**
138     * Process a MessageContext.
139     */

140    public void invoke(MessageContext context) throws AxisFault
141    {
142       // Should we reap timed out sessions?
143
long curTime = System.currentTimeMillis();
144       boolean reap = false;
145
146       // Minimize synchronicity, just check in here, do reap later.
147
synchronized (this)
148       {
149          if (curTime > lastReapTime + (reapPeriodicity * 1000))
150          {
151             reap = true;
152             lastReapTime = curTime;
153          }
154       }
155
156       if (reap)
157       {
158          Set JavaDoc entries = activeSessions.entrySet();
159          Set JavaDoc victims = new HashSet JavaDoc();
160          Object JavaDoc key;
161          Iterator JavaDoc i;
162          for (i = entries.iterator(); i.hasNext();)
163          {
164             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)i.next();
165             key = entry.getKey();
166             SimpleSession session = (SimpleSession)entry.getValue();
167             if ((curTime - session.getLastAccessTime()) >
168                     (session.getTimeout() * 1000))
169             {
170                log.debug(Messages.getMessage("timeout00",
171                        key.toString()));
172
173                // Don't modify the hashtable while we're iterating.
174
victims.add(key);
175             }
176          }
177
178          // Now go remove all the victims we found during the iteration.
179
for (i = victims.iterator(); i.hasNext();)
180          {
181             key = i.next();
182             SimpleSession session = (SimpleSession)activeSessions.get(key);
183             activeSessions.remove(key);
184
185             // For each victim, swing through the data looking for
186
// ServiceLifecycle objects, and calling destroy() on them.
187
// FIXME : This cleanup should probably happen on another
188
// thread, as it might take a little while.
189
Enumeration JavaDoc keys = session.getKeys();
190             while (keys != null && keys.hasMoreElements())
191             {
192                String JavaDoc keystr = (String JavaDoc)keys.nextElement();
193                Object JavaDoc obj = session.get(keystr);
194                if (obj != null && obj instanceof ServiceLifecycle JavaDoc)
195                {
196                   ((ServiceLifecycle JavaDoc)obj).destroy();
197                }
198             }
199          }
200       }
201
202       if (context.isClient())
203       {
204          doClient(context);
205       }
206       else
207       {
208          doServer(context);
209       }
210    }
211
212    /**
213     * Client side of processing.
214     */

215    public void doClient(MessageContext context) throws AxisFault
216    {
217       if (context.getPastPivot())
218       {
219          // This is a response. Check it for the session header.
220
Message msg = context.getResponseMessage();
221          if (msg == null)
222             return;
223          SOAPEnvelopeAxisImpl env = msg.getSOAPEnvelope();
224          SOAPHeaderElementAxisImpl header = env.getHeaderByName(SESSION_NS,
225                  SESSION_LOCALPART);
226          if (header == null)
227             return;
228
229          // Got one!
230
try
231          {
232             Long JavaDoc id = (Long JavaDoc)header.
233                     getValueAsType(Constants.XSD_LONG);
234             // Store it away.
235
AxisEngine engine = context.getAxisEngine();
236             engine.setOption(SESSION_ID, id);
237             // Note that we processed this header!
238
header.setProcessed(true);
239          }
240          catch (Exception JavaDoc e)
241          {
242             throw AxisFault.makeFault(e);
243          }
244       }
245       else
246       {
247          AxisEngine engine = context.getAxisEngine();
248          Long JavaDoc id = (Long JavaDoc)engine.getOption(SESSION_ID);
249          if (id == null)
250             return;
251
252          // We have a session ID, so insert the header
253
Message msg = context.getRequestMessage();
254          if (msg == null)
255             throw new AxisFault(Messages.getMessage("noRequest00"));
256
257          SOAPEnvelopeAxisImpl env = msg.getSOAPEnvelope();
258          SOAPHeaderElementAxisImpl header = new SOAPHeaderElementAxisImpl(SESSION_NS,
259                  SESSION_LOCALPART,
260                  id);
261          env.addHeader(header);
262       }
263    }
264
265    /**
266     * Server side of processing.
267     */

268    public void doServer(MessageContext context) throws AxisFault
269    {
270       if (context.getPastPivot())
271       {
272          // This is a response. Add the session header if we have an
273
// ID.
274
Long JavaDoc id = (Long JavaDoc)context.getProperty(SESSION_ID);
275          if (id == null)
276             return;
277
278          Message msg = context.getResponseMessage();
279          if (msg == null)
280             return;
281          SOAPEnvelopeAxisImpl env = msg.getSOAPEnvelope();
282          SOAPHeaderElementAxisImpl header = new SOAPHeaderElementAxisImpl(SESSION_NS,
283                  SESSION_LOCALPART,
284                  id);
285          env.addHeader(header);
286       }
287       else
288       {
289          // Request. Set up the session if we find the header.
290
Message msg = context.getRequestMessage();
291          if (msg == null)
292             throw new AxisFault(Messages.getMessage("noRequest00"));
293
294          SOAPEnvelopeAxisImpl env = msg.getSOAPEnvelope();
295          SOAPHeaderElementAxisImpl header = env.getHeaderByName(SESSION_NS,
296                  SESSION_LOCALPART);
297          Long JavaDoc id;
298
299          if (header != null)
300          {
301             // Got one!
302
try
303             {
304                id = (Long JavaDoc)header.
305                        getValueAsType(Constants.XSD_LONG);
306             }
307             catch (Exception JavaDoc e)
308             {
309                throw AxisFault.makeFault(e);
310             }
311          }
312          else
313          {
314             id = getNewSession();
315          }
316
317          SimpleSession session = (SimpleSession)activeSessions.get(id);
318          if (session == null)
319          {
320             // Must have timed out, get a new one.
321
id = getNewSession();
322             session = (SimpleSession)activeSessions.get(id);
323          }
324
325          // This session is still active...
326
session.touch();
327
328          // Store it away in the MessageContext.
329
context.setSession(session);
330          context.setProperty(SESSION_ID, id);
331       }
332    }
333
334    /**
335     * Generate a new session, register it, and return its ID.
336     *
337     * @return the new session's ID for later lookup.
338     */

339    private synchronized Long JavaDoc getNewSession()
340    {
341       Long JavaDoc id = SessionUtils.generateSession();
342       SimpleSession session = new SimpleSession();
343       session.setTimeout(defaultSessionTimeout);
344       activeSessions.put(id, session);
345       return id;
346    }
347
348    /**
349     * Set the reaper periodicity in SECONDS
350     * <p/>
351     * Convenience method for testing.
352     * <p/>
353     * !!! TODO: Should be able to set this via options on the Handler
354     * or perhaps the engine.
355     */

356    public void setReapPeriodicity(long reapTime)
357    {
358       reapPeriodicity = reapTime;
359    }
360
361    /**
362     * Set the default session timeout in SECONDS
363     * <p/>
364     * Again, for testing.
365     */

366    public void setDefaultSessionTimeout(int defaultSessionTimeout)
367    {
368       this.defaultSessionTimeout = defaultSessionTimeout;
369    }
370 }
371
Popular Tags