FileDocCategorySizeDatePackage
SimpleSessionHandler.javaAPI DocApache Axis 1.411635Sat Apr 22 18:57:28 BST 2006org.apache.axis.handlers

SimpleSessionHandler

public class SimpleSessionHandler extends BasicHandler
This handler uses SOAP headers to do simple session management.

Essentially, you install it on both the request and response chains of your service, on both the client and the server side.

ON THE SERVER:

  • The REQUEST is checked for a session ID header. If present, we look up the correct SimpleSession. If not, we create a new session. In either case, we install the session into the MessageContext, and put its ID in the SESSION_ID property.
  • The RESPONSE gets a session ID header tacked on, assuming we found a SESSION_ID property in the MessageContext.

ON THE CLIENT:

  • The RESPONSE messages are checked for session ID headers. If present, we pull the ID out and insert it into an option in the AxisClient. This works because a given Call object is associated with a single AxisClient. However, we might want to find a way to put it into the Call object itself, which would make a little more sense. This would mean being able to get to the Call from the MC, i.e. adding a getCall() API (which would only work on the client side)....
  • When REQUESTS are generated, we look to see if an ID option is present in the AxisClient associated with the MessageContext. If so, we insert a session ID header with the appropriate ID.

SimpleSessions are "reaped" periodically via a very simplistic mechanism. Each time the handler is invoke()d we check to see if more than reapPeriodicity milliseconds have elapsed since the last reap. If so, we walk the collection of active Sessions, and for each one, if it hasn't been "touched" (i.e. had a getProperty() or setProperty() performed) in longer than its timeout, we remove it from the collection.

author
Glen Daniels (gdaniels@apache.org)

Fields Summary
protected static Log
log
public static final String
SESSION_ID
public static final String
SESSION_NS
public static final String
SESSION_LOCALPART
public static final QName
sessionHeaderName
private Hashtable
activeSessions
private long
reapPeriodicity
private long
lastReapTime
private int
defaultSessionTimeout
Constructors Summary
Methods Summary
public voiddoClient(org.apache.axis.MessageContext context)
Client side of processing.

        if (context.getPastPivot()) {
            // This is a response.  Check it for the session header.
            Message msg = context.getResponseMessage();
            if (msg == null)
                return;
            SOAPEnvelope env = msg.getSOAPEnvelope();
            SOAPHeaderElement header = env.getHeaderByName(SESSION_NS,
                                                           SESSION_LOCALPART);
            if (header == null)
                return;
            
            // Got one!
            try {
                Long id = (Long)header.
                             getValueAsType(Constants.XSD_LONG);
                // Store it away.
                AxisEngine engine = context.getAxisEngine();
                engine.setOption(SESSION_ID, id);
                // Note that we processed this header!
                header.setProcessed(true);
            } catch (Exception e) {
                throw AxisFault.makeFault(e);
            }
        } else {
            AxisEngine engine = context.getAxisEngine();
            Long id = (Long)engine.getOption(SESSION_ID);
            if (id == null)
                return;
            
            // We have a session ID, so insert the header
            Message msg = context.getRequestMessage();
            if (msg == null)
                throw new AxisFault(Messages.getMessage("noRequest00"));
            
            SOAPEnvelope env = msg.getSOAPEnvelope();
            SOAPHeaderElement header = new SOAPHeaderElement(SESSION_NS,
                                                             SESSION_LOCALPART,
                                                             id);
            env.addHeader(header);
        }
    
public voiddoServer(org.apache.axis.MessageContext context)
Server side of processing.

        if (context.getPastPivot()) {
            // This is a response.  Add the session header if we have an
            // ID.
            Long id = (Long)context.getProperty(SESSION_ID);
            if (id == null)
                return;
            
            Message msg = context.getResponseMessage();
            if (msg == null)
                return;
            SOAPEnvelope env = msg.getSOAPEnvelope();
            SOAPHeaderElement header = new SOAPHeaderElement(SESSION_NS,
                                                             SESSION_LOCALPART,
                                                             id);
            env.addHeader(header);
        } else {
            // Request.  Set up the session if we find the header.
            Message msg = context.getRequestMessage();
            if (msg == null)
                throw new AxisFault(Messages.getMessage("noRequest00"));
            
            SOAPEnvelope env = msg.getSOAPEnvelope();
            SOAPHeaderElement header = env.getHeaderByName(SESSION_NS,
                                                           SESSION_LOCALPART);
            Long id;
            
            if (header != null) {
                // Got one!
                try {
                    id = (Long)header.
                            getValueAsType(Constants.XSD_LONG);
                } catch (Exception e) {
                    throw AxisFault.makeFault(e);
                }
            } else {
                id = getNewSession();
            }
            
            SimpleSession session = (SimpleSession)activeSessions.get(id);
            if (session == null) {
                // Must have timed out, get a new one.
                id = getNewSession();
                session = (SimpleSession)activeSessions.get(id);
            }

            // This session is still active...
            session.touch();
            
            // Store it away in the MessageContext.
            context.setSession(session);
            context.setProperty(SESSION_ID, id);
        }
    
private synchronized java.lang.LonggetNewSession()
Generate a new session, register it, and return its ID.

return
the new session's ID for later lookup.

        Long id = SessionUtils.generateSession();
        SimpleSession session = new SimpleSession();
        session.setTimeout(defaultSessionTimeout);
        activeSessions.put(id, session);
        return id;
    
public voidinvoke(org.apache.axis.MessageContext context)
Process a MessageContext.


            
         
    
        // Should we reap timed out sessions?
        long curTime = System.currentTimeMillis();
        boolean reap = false;
        
        // Minimize synchronicity, just check in here, do reap later.
        synchronized (this) {
            if (curTime > lastReapTime + (reapPeriodicity * 1000)) {
                reap = true;
                lastReapTime = curTime;
            }
        }
        
        if (reap) {
            Set entries = activeSessions.entrySet();
            Set victims = new HashSet();
            Object key;
            Iterator i;
            for (i = entries.iterator(); i.hasNext();) {
                Map.Entry entry = (Map.Entry) i.next();
                key = entry.getKey();
                SimpleSession session = (SimpleSession) entry.getValue();
                if ((curTime - session.getLastAccessTime()) >
                     (session.getTimeout() * 1000)) {
                    log.debug(Messages.getMessage("timeout00",
                                                        key.toString()));

                    // Don't modify the hashtable while we're iterating.
                    victims.add(key);
                }
            }

            // Now go remove all the victims we found during the iteration.
            for (i = victims.iterator(); i.hasNext();) {
                key = i.next();
                SimpleSession session = (SimpleSession)activeSessions.get(key);
                activeSessions.remove(key);

                // For each victim, swing through the data looking for
                // ServiceLifecycle objects, and calling destroy() on them.
                // FIXME : This cleanup should probably happen on another
                //         thread, as it might take a little while.
                Enumeration keys = session.getKeys();
                while (keys != null && keys.hasMoreElements()) {
                    String keystr = (String)keys.nextElement();
                    Object obj = session.get(keystr);
                    if (obj != null && obj instanceof ServiceLifecycle) {
                        ((ServiceLifecycle)obj).destroy();
                    }
                }
            }
        }
        
        if (context.isClient()) {
            doClient(context);
        } else {
            doServer(context);
        }
    
public voidsetDefaultSessionTimeout(int defaultSessionTimeout)
Set the default session timeout in SECONDS Again, for testing.

        this.defaultSessionTimeout = defaultSessionTimeout;
    
public voidsetReapPeriodicity(long reapTime)
Set the reaper periodicity in SECONDS Convenience method for testing. !!! TODO: Should be able to set this via options on the Handler or perhaps the engine.

        reapPeriodicity = reapTime;