The Source for Java Technology Collaboration
User: Password:



Rama Pulavarthi

Rama Pulavarthi's Blog

Maintaining Session With JAX-WS

Posted by ramapulavarthi on June 07, 2006 at 10:26 AM | Comments (8)

Web Services are stateless by default because of the underlying HTTP protocol. The server processes each web service request as a new interaction even though it is from the same client. To have a knowledge about previous requests, Server would need to maintain state about the client through some sort. Maintaining state/session would have extra load on the client/server in terms of time and memory. Even then, sometimes stateful web services can be useful for conversational message exchange patterns, where multiple message exchanges are required between client and server.

By default JAX-WS Web Services and Clients are stateless. When a client makes a request, the server responds and sets a cookie on the connection, if it participates in a session. But, the JAX-WS client ignores that cookie and the server treats subsequent requests as new interaction. When the session is enabled, JAX-WS client sends the same cookie with each subsequent request so that server can keep track of the client session.

Lets start off with a simple Counter Web Service which tracks the user requests. Each time client calls getCounter(), the service returns the counter after incrementing by 1.

@WebService
public class Hello {
    int counter = 0;
    public int getCounter() {
        // incorrect – not unique for each client session.
        return counter++;
    }
}

Enabling session support for your web service would require little effort on the server and client.

Accessing Session on Server:

After the service endpoint is instantiated, the runtime system is required to initialize the endpoint instance before any requests can be serviced. If you are familiar with JAX-RPC based Web Service, enabling session support would require the service to implement javax.xml.rpc.server.ServiceLifecycle interface and its lifecycle methods init() and destroy(). The JAX-RPC runtime would pass the ServletEndpointContext which gives access to the message context, session, servlet context associated with each method invocation.

JAX-WS uses some handy annotations defined by Common Annotations for the Java Platform (JSR 250), to inject the Web Service context and declaring lifecycle methods. Web ServiceContext holds the context information pertaining to a request being served. You don’t need to implement javax.xml.rpc.server.ServiceLifecycle. With JAX-WS Web Service all you need to do is mark a field or method with @Resource. The type element MUST be either java.lang.Object (the default) or javax.xml.ws.WebServiceContext. If the former, then the resource will be injected into a field or a method. In this case, the type of the field or the type of the JavaBeans property defined by the method MUST be javax.xml.ws.WebServiceContext. From the WebServiceContext, message context pertaining to the the current request can be accessed. For more information on how message context can be used to share metadata is explained in this article. The following snippet from Hello Service shows the usage of annotations.

@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;

    }
}

JSR-250 also defines annotations for lifecycle methods, @PostConstruct and @PreDestroy. These lifecycle annotations (methods) can be used for effectively managing memory resources. After the resource injection is done, methods marked with @PostConstruct (similar to init method in JAX-RPC) are invoked before servicing any requests. Similarly methods marked with @PreDestroy are invoked before the service is destroyed.

Enabling Session on Client:

Session can be maintained just by setting the property “MessageContext.SESSION_MAINTAIN_PROPERTY” to true in the request context of the proxy/dispatch instance. For more information about setting properties in request context refer to this article.

Hello proxy = new HelloService().getHelloPort();
((BindingProvider)proxy).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY,true);
int result = proxy.getCounter();
System.out.println(result);
result = proxy.getCounter();
System.out.println(result);

The above snippet from the HelloClient, prints 1 and 2 respectively.As shown above maintaining session with JAX-WS is easy.


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

  • How can we control the session time out?

    Posted by: technohunter on June 09, 2006 at 01:43 AM

  • I suppose that does only work if my webservice endpoint lives in the web container and not in the EJB container?! I.e., am i right in assuming that the following does *not* work?!:


    @WebService
    @EJB
    public class Hello {
    @Resource
    private WebServiceContext wsContext;

    public int getCounter() {
    // yada yada
    }
    }


    This is important because usually i want to implement my webservice endpoints as EJBs.

    As an aside, i hope i'm not the only one who considers implementing a stateful service *like this* a depressing set-back compared to the level of abstraction and comfort stateful session beans have been providing for years.

    cheers,
    gerald

    http://www.gerald-loeffler.net

    Posted by: geraldloeffler on June 09, 2006 at 01:08 PM

  • You can specify the session timeout in web.xml

    <web-app>
    <session-config>
    <session-timeout>60</session-timeout>
    </session-config>
    ............
    </web-app>


    Or

    You could set it on HttpSession object like HttpSession.setMaxInactiveInterval(int interval);

    Posted by: ramapulavarthi on June 22, 2006 at 06:24 PM

  • I guess this webservice is only consumable by a Java Application. Is there a way a .NET client cal also consume this webservice, with state?

    please provide with me some coding.

    Posted by: lordhiru on August 21, 2006 at 07:17 PM

  • Interesting, but it doesn't seem to work. Using tcpmon I see different JSESSIONID's for each request and the objects I store in the session are not persistent. I am using Sun Java System Application Server Platform Edition 9.0_01 (build b14) and the jars that come with it.

    Posted by: travbow on February 01, 2007 at 09:30 AM

  • What would cause the MessageContext to not be populated with a SERVLET_REQUEST object? I am using the JDK 6 http server to deploy a web service. Is this the reason there is no SERVLET_REQUEST object? If so, is there another way I can obtain the calling client's IP address?

    Posted by: jesterfred on June 22, 2007 at 08:52 AM

  • Hello, how can we know the sessions which are active on server-side ?

    Posted by: matof on May 02, 2008 at 04:07 AM

  • Rama
    How can i load a java bean in application scope since web application start and then access it from a web service.

    Posted by: ksimon on June 19, 2008 at 07:21 AM



Only logged in users may post comments. Login Here.


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