The Source for Java Technology Collaboration
User: Password:



Kohsuke Kawaguchi

Kohsuke Kawaguchi's Blog

Bringing state back to web services: HttpSession-scope

Posted by kohsuke on October 17, 2006 at 09:03 AM | Comments (8)

Traditionally JAX-WS has never taken advantage of object state, just like servlet. That is, the container creates only one instance of your service class, and then have it serve all the requests concurrently. This makes it impossible to set values to instance fields, as you'll experience concurrency problem as soon as multiple threads hit your service.

So all too often the service code starts to look more like C code, not Java code, and I didn't like this at all. Since I started helping the JAX-WS RI, I've been trying to fix this. Yesterday, I finally managed to write one.

On HTTP, session is often used to store state. This technique is still useful for web services over HTTP. JAX-WS lets you do this today, but as you can see in Rama's example, this is not pretty at all. Especially the server side, which I quote below for your reference:

@WebService
public class Hello {
    @Resource
    private WebServiceContext wsContext;
    public int getCounter(){
        MessageContext mc = wsContext.getMessageContext();
        HttpSession session = ((javax.servlet.http.HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST)).getSession();
        // Get a session property "counter" from context
        if (session == null)
            throw new WebServiceException("No session in WebServiceContext");
        Integer counter = (Integer)session.getAttribute("counter");
        if (counter == null) {
            counter = new Integer(0);
            System.out.println("Starting the Session");
        }
        counter = new Integer(counter.intValue() + 1);
        session.setAttribute("counter", counter);
        return counter;

    }
}

Instead of writing this much code, with JAX-WS RI 2.1, you can do this:

@HttpSessionScope @WebService
public class Hello {
    int counter = 0;
    public int getCounter() {
        return counter++;
    }
}

The @com.sun.xml.ws.developer.servlet.HttpSessionScope annotation tells the JAX-WS RI to create one instance of Hello per each HTTP session. No need to mess with WebServiceContext, nor with HttpSession manually. It's all nicely typed and concise.

Not only that, but what I really like about this is that you can do something like this completely outside the JAX-WS RI. This is based on publicly available extension point in the JAX-WS RI 2.1 called InstanceResolver. This provides a pluggability point where 3rd party could control how the JAX-WS RI dispatches incoming requests to service instances, and I only needed to write a little more code to implement this logic.

Then I define HttpSessionScope annotation with JAX-WS RI's meta annotation InstanceResolverAnnotation, to connect all those things together.

I've barely scratched the surface with this mechanism. There's already a variant of this that takes advantage of WS-Addressing (which is the "proper" way of doing stateful web services), and we can write another that loads instances from Spring, which allows you to take advantage of all its DI features and AOJ mechanisms. So stay tuned for future entries.

To play with this feature today, go download the JAX-WS RI 2.1 nightly. Also, I think we'll be posting a new EA relatively soon.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Any way to use this outside the scope of web services (which I don't want to use)? I'd like to see this working for anything built on top of the servlet API.

    Gili

    Posted by: cowwoc on October 18, 2006 at 07:25 AM


  • I'll ask our servlet folks what they think about something like this. But IU thought nowadays you are not really supposed to be writing servlets by yourself anyway — you should be programming at higher-layer.


    If you like something like this, I think you might like my stapler project, which I use to implement hudson.


    You can very easily allocate a part of the URL space for per-session object tree.

    Posted by: kohsuke on October 18, 2006 at 07:39 AM

  • this is exactly what i think is wrong annotations. everyone is using it to add convenience functionality, so we're heading towards a place where we'll have lots and lots of exceptions disguised as one "rule". that isn't to say what you have isn't an attractive idea; i just wish we had something more consistent to work with than weak macros.

    Posted by: ilazarte on October 18, 2006 at 08:18 PM

  • ilazarte — I'd like to better understand what you are saying. I'm not sure what you mean by "weak macro", but I guess essentially you are saying that you don't like a declarative programming model where the services are provided from outside, instead of having code to do it? Or am I missing your point?

    Posted by: kohsuke on October 19, 2006 at 07:40 AM

  • Hi, I looked at your code and implemented something similar to grab my fully configured WebServices from a Spring-ApplicationContext... only needs some polishing.

    Is there a similar way to resolve Handlers from anywhere?
    I'd like to configure those in Spring too!

    Thanx for that great technology!

    Posted by: dumpshock111 on November 17, 2006 at 12:59 AM

  • I'm following up with dumpshock111 in dev@jax-ws.dev.java.net. If you are intersted in this, come join the JAX-WS dev list.

    Posted by: kohsuke on November 17, 2006 at 09:10 AM

  • When we talk about webservices, they are supposed to be transport agnostic, ie. I should be able to use my POJO that I define using a webservice annotation accessed over JMS, IIOP, HTTP or anything else.
    Webservice implementations do allow us to use any transport layer implementation. Isn't putting a HTTPSessionScope annotation in the class and depending upon it too restrictive ?
    Shouldn't there be a better way of managing client state ? For eg:- building and using a singleton POJO as default mechanism with an ability to override by users favoring a more sophisticated implementation ?

    Posted by: n_sachin1 on March 29, 2007 at 03:59 AM


  • Yeah, from transport independence perspective, you don't want to use @HttpSessionScope. For that, you could use our "stateful web service" support based on WS-Addressing (see my other post), or if you know of other standards (I've heard WS-Context does something similar), we can probably quickly implement a custom scope annotation for those.


    But it's also true that HTTP is still a dominant transport, and being able to take advantages of HTTP session is often very convenient.


    So it's the right tool for the right job kind of things.

    Posted by: kohsuke on March 29, 2007 at 09:43 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds