You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Pierre Buyle <pi...@irislink.com> on 2007/11/13 18:08:05 UTC

Re: Sharing session with multiple services

I've the same requirements for my services. A session is initialized on the
first call to a services and should be shared with others. On the server
side, I've written Interceptors to fetch and store the session data in
message.getExchange().getSession().

Using soapUI I can manually set the JSESSIONID cookie in the HTTP Header nad
the session is effectivly maintained across services.

Since I don't want client code to care about the session, I'm trying to
implement session handling in a JAX-WS Handler. Here is my code
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SessionHandler implements Handler<SOAPMessageContext>
{
	private static String sessionCookie = null;
	private static final String SET_COOKIE = "Set-Cookie";
	private static final String COOKIE = "Cookie";
	private static final String JSESSIONID = "JSESSIONID";
	private static Pattern cookiePattern =
Pattern.compile("([^\\p{Cntrl}\\s]+)=(\\w+|\".*\").*");
	
        private Log log =  LogFactory.getLog(SessionHandler.class);
	
	public void close(MessageContext messageContext)
	{

	}

	public boolean handleFault(SOAPMessageContext messageContext)
	{
		return false;
	}

	public boolean handleMessage(SOAPMessageContext messageContext)
	{
		if(((Boolean)
messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)))
			return handleOutMessage(messageContext);
		else
			return handleInMessage(messageContext);
	}
	
	private boolean handleOutMessage(SOAPMessageContext messageContext)
	{
		@SuppressWarnings("unchecked")
		Map<String, List<String>> headers = (Map<String, List<String>>)
messageContext.get(MessageContext.HTTP_REQUEST_HEADERS);
		if(sessionCookie!=null)
		{
			if(headers==null)
			{
				headers = new HashMap<String, List<String>>();
				messageContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
			}
			List<String> cookie = headers.get(COOKIE);
			if(cookie==null)
			{
				cookie = new ArrayList<String>();
				headers.put(COOKIE, cookie);
			}
			cookie.add(sessionCookie);
			log.debug("Cookie added to HTTP Header: " + sessionCookie);
		}
		return true;
	}

	private boolean handleInMessage(SOAPMessageContext messageContext)
	{
		@SuppressWarnings("unchecked")
		Map<String, List<String>> headers = (Map<String, List<String>>)
messageContext.get(MessageContext.HTTP_RESPONSE_HEADERS);
		if(headers!=null)
		{
			List<String> setCookie = headers.get(SET_COOKIE);
			if(setCookie!=null)
			{
				for(String cookie: setCookie)
				{
					Matcher cookieMatcher = cookiePattern.matcher(cookie);
					if(cookieMatcher.find())
					{
						String name = cookieMatcher.group(1);
						String value = cookieMatcher.group(2);
						if(name.toUpperCase().equals(JSESSIONID))
						{
							sessionCookie = name + '=' + value;
							log.debug("Cookie retrieved from HTTP Header:" + sessionCookie);
						}
					}
				}
			}
		}
		return true;
	}
}
As you can see, it simply store the JSESSIONID cookie in a static field when
found in a in-message and put it back in out-messages.

This handler is added to the handler chain of each of my JAX-WS Proxy like
this:
	...

((BindingProvider)client).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY,
true);
	List<Handler> handlers =
((BindingProvider)client).getBinding().getHandlerChain();
	handlers.add(sessionHandler);
	...

But it doesn't work. Even if the "cookie.add(sessionCookie);" line is
executed with the right value, I don't see any "Cookie" header in tcpmon.

Does someone have any idea why it doesn't work ?


dkulp wrote:
> 
> 
> On the client side, you should be able to get the transport headers from 
> the response context.   From there, you could pull the Cookie header out 
> and do the cooking processing yourself.    On the second proxy, you 
> would set the request headers into the request context.   There wouldn't 
> need to be any interceptor involved.
> 
> In pseudo code:
> 
> port.makeACallToTheService(....);
> BindingProvider bp = (BindingProvider)port;
> Map<String, List<String>> headers = bp.getResponseContext().
>    get("javax.xml.ws.http.response.headers");
> 
> ...   get the cookie from it .....
> 
> bp = (BindingProvider)port2;
> Map<String, List<String>> headers = bp.getRequestContext().
>    get("javax.xml.ws.http.request.headers");
> if (headers == null) {
>     headers = new HashMap<String, List<String>>();
>     bp.getRequestContext().put("javax......", headers);
> }
> headers.put("cookie stuff"....);
> port2.makeSecondCall(...);
> 
> 
> Dan
> 
> 
> 
> On Tuesday 18 September 2007, John McLaughlin wrote:
>> Hi,
>>
>> 	I've just started to look at CXF, and have successfully managed to
>> quickly develop/deploy.
>>
>> 	The scenario I have is that I will have multiple web services running
>> in Tomcat, and I want to maintain a session across them. I'm defining
>> the services using JAX-WS (newbie here too!)
>>
>> 	I can set BindingProvider.SESSION_MAINTAIN_PROPERTY on the client
>> side to true, and this works fine on an individual proxy with
>> JSESSIONID sent received, and I can access the appropriate session on
>> the server side. However, when I call a second service it results in
>> another session being started.
>>
>> 	I've been trawling through APIs and the mail archives all afternoon,
>> but haven't come up with any answers. Is it possible to retrieve the
>> JSESSIONID from the first service and stuff it into the second
>> service? I'm guessing an Interceptor on the client would be the way to
>> go, but I haven't been able to find any examples. Failing all that,
>> would it be a valid approach to add an Interceptor which would
>> add/extract a header on messages?
>>
>> 	I'd prefer to go with the JSESSIONID as I can let Tomcat take care of
>> the session management, so if anybody can point me in the right
>> direction, I'd much appreciate it!
>>
>> Thanks,
>>
>> John
> 
> 
> 
> -- 
> J. Daniel Kulp
> Principal Engineer
> IONA
> P: 781-902-8727    C: 508-380-7194
> daniel.kulp@iona.com
> http://www.dankulp.com/blog
> 
> 

-- 
View this message in context: http://www.nabble.com/Sharing-session-with-multiple-services-tf4475754.html#a13730346
Sent from the cxf-user mailing list archive at Nabble.com.


Re: Sharing session with multiple services

Posted by Pierre Buyle <pi...@irislink.com>.
Hi,

I did it with a CFX Interceptor. The code looks a lot like my JAX-WS
Handler. The headers Map is retrieved with
message.get(Message.PROTOCOL_HEADERS). And
message.get(Message.INBOUND_MESSAGE) is used as test to select between
handleInMessage and handleOutMessage.

I had to try several phases. None of (PRE/USER/POST)_PROTOCOL did work, but
PRE_LOGICAL does.

According to the documentation, JAX-WS Handlers are in one of the
(PRE/USER/POST)_PROTOCOL phase. If Interceptors cannot add HTTP headers in
this phase, I understand why my handler didn't work. But it doesn't seems
right to me since JAX-WS Handlers should be able to do it.


Pierre Buyle wrote:
> 
> I've the same requirements for my services. A session is initialized on
> the first call to a services and should be shared with others. On the
> server side, I've written Interceptors to fetch and store the session data
> in message.getExchange().getSession().
> 
> Using soapUI I can manually set the JSESSIONID cookie in the HTTP Header
> nad the session is effectivly maintained across services.
> 
> Since I don't want client code to care about the session, I'm trying to
> implement session handling in a JAX-WS Handler. Here is my code
> [...]
> As you can see, it simply store the JSESSIONID cookie in a static field
> when found in a in-message and put it back in out-messages.
> 
> This handler is added to the handler chain of each of my JAX-WS Proxy like
> this:
> 	...
> 
> ((BindingProvider)client).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY,
> true);
> 	List<Handler> handlers =
> ((BindingProvider)client).getBinding().getHandlerChain();
> 	handlers.add(sessionHandler);
> 	...
> 
> But it doesn't work. Even if the "cookie.add(sessionCookie);" line is
> executed with the right value, I don't see any "Cookie" header in tcpmon.
> 
> Does someone have any idea why it doesn't work ?
> 
> 
> dkulp wrote:
>> 
>> 
>> On the client side, you should be able to get the transport headers from 
>> the response context.   From there, you could pull the Cookie header out 
>> and do the cooking processing yourself.    On the second proxy, you 
>> would set the request headers into the request context.   There wouldn't 
>> need to be any interceptor involved.
>> 
> 
> 

-- 
View this message in context: http://www.nabble.com/Sharing-session-with-multiple-services-tf4475754.html#a13750532
Sent from the cxf-user mailing list archive at Nabble.com.