All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.axis.handlers.SimpleSessionHandler Maven / Gradle / Ivy

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

package org.apache.axis.handlers;

import org.apache.axis.AxisEngine;
import org.apache.axis.AxisFault;
import org.apache.axis.Constants;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.axis.message.SOAPHeaderElement;
import org.apache.axis.session.SimpleSession;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.SessionUtils;
import org.apache.commons.logging.Log;

import javax.xml.namespace.QName;
import javax.xml.rpc.server.ServiceLifecycle;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/** 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 ([email protected]) */ public class SimpleSessionHandler extends BasicHandler { protected static Log log = LogFactory.getLog(SimpleSessionHandler.class.getName()); public static final String SESSION_ID = "SimpleSession.id"; public static final String SESSION_NS = "http://xml.apache.org/axis/session"; public static final String SESSION_LOCALPART = "sessionID"; public static final QName sessionHeaderName = new QName(SESSION_NS, SESSION_LOCALPART); private Hashtable activeSessions = new Hashtable(); // Reap timed-out sessions on the first request after this many // seconds. private long reapPeriodicity = 30; private long lastReapTime = 0; // By default, sessions time out after 1 minute of inactivity (60 sec) private int defaultSessionTimeout = 60; /** * Process a MessageContext. */ public void invoke(MessageContext context) throws AxisFault { // 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); } } /** * Client side of processing. */ public void doClient(MessageContext context) throws AxisFault { 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); } } /** * Server side of processing. */ public void doServer(MessageContext context) throws AxisFault { 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); } } /** * Generate a new session, register it, and return its ID. * * @return the new session's ID for later lookup. */ private synchronized Long getNewSession() { Long id = SessionUtils.generateSession(); SimpleSession session = new SimpleSession(); session.setTimeout(defaultSessionTimeout); activeSessions.put(id, session); return id; } /** * 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. */ public void setReapPeriodicity(long reapTime) { reapPeriodicity = reapTime; } /** * Set the default session timeout in SECONDS * * Again, for testing. */ public void setDefaultSessionTimeout(int defaultSessionTimeout) { this.defaultSessionTimeout = defaultSessionTimeout; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy