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.