An ongoing debate exists within the Web services community on whether the nature of Web services is stateless. While some developers propose specifications such as WS-Resource Framework (see Resources) to define stateful Web services, the JAX-RPC specification in wide use today (see Resources) primarily deals with the stateless services. Stateless means that an invocation to the Web service has no correlation to prior interactions, and no information from the current activity is saved for future interactions.
You can see this from the fact that common JAX-RPC service endpoint components such as JavaBeans and stateless session Enterprise JavaBeans components do not maintain state information. That being said, depending on where the service endpoints are deployed, you can still leverage the native session support from underlying transport protocols and build a stateful Web service. This article shows how to use the session capabilities of HTTP in JAX-RPC applications as deployed onto the servlet container. It demonstrates this in a simple shopping cart Web service, built for this purpose.
Example: shopping cart service
Listing 1 defines a simple shopping cart Web service that allows the shopper to add, remove, and query items in the cart. One requirement is that this shopping cart service maintains selected items during the entire shopping period until the shopper checks out. The rest of this article shows how this simple yet stateful service can be implemented using various JAX-RPC techniques.
Listing 1. Shopping cart interface
package shopping;
public interface Cart extends java.rmi.Remote {
public void addItem(String item) throws java.rmi.RemoteException;
public void removeItem(String item) throws java.rmi.RemoteException;
public int getItemNumber() throws java.rmi.RemoteException;
public void checkout() throws java.rmi.RemoteException, shopping.NoUserSessionFault;
}
|
The service is implemented in two steps:
- Implement the
ServiceLifecycleinterface. - Manipulate the session data.
Implement the ServiceLifecyle interface
JAX-RPC defines a javax.xml.rpc.server.ServiceLifecyle interface.
If a service implementation class
implements this interface, the JAX-RPC runtime system is required to manage
the life cycle of the corresponding service endpoint instances. This ServiceLifecyle
interface has two methods: init
and destroy. The init method takes a
"context" parameter of the generic type java.lang.Object, but any compliant JAX-RPC
runtime system is required to pass a javax.xml.rpc.server.ServletEndpointContext
instance if services endpoints are deployed onto a servlet-container-based JAX-RPC runtime system.
In our example, the service implementation class
CartSoapBindingImpl (see Listing 2) implements such
a ServiceLifecyle interface.
After the implementation instance is instantiated, JAX-RPC runtime invokes its
init method which casts the context parameter to the type
javax.xml.rpc.server.ServletEndpointContext. This is allowed
because the shopping cart service is servlet-based. This context
object is then saved as a private field so that subsequent calls can use it to obtain the HttpSession. As a cleanup, this context object
is set to null once destroy method is called.
Listing 2. Implement the
ServiceLifecycle interface
public class CartSoapBindingImpl implements shopping.Cart, ServiceLifecycle {
private ServletEndpointContext jaxrpcContext;
public void init(Object context) throws ServiceException {
jaxrpcContext = (ServletEndpointContext) context;
}
public void destroy() {
jaxrpcContext = null;
}
...
}
|
The javax.xml.rpc.server.ServletEndpointContext
interface contains a few methods. The one pertaining to this article's topic is getHttpSession(),
which returns a javax.servlet.http.HttpSession instance.
For each shopping cart service method, it first calls this getHttpSession
method against the previously cached ServletEndpointContext to
get hold of the HttpSession object. Once HttpSession is available,
the service implementation can retrieve the user session data from the HttpSession object,
just like regular servlets do (see Listing 3). Note that the SessionData
class defined in Listing 3 is a user-defined data structure to store
various shopping cart information (Click the code icon at the top or bottom of this article).
Listing 3. Retrive
HTTPSession from ServletEndpointContext
public class CartSoapBindingImpl implements shopping.Cart, ServiceLifecycle {
private ServletEndpointContext jaxrpcContext;
...
public void addItem(java.lang.String item)
throws java.rmi.RemoteException {
getSessionData().addItem(item);
}
// SessionData is a utility class to store all the shopping cart related information
private SessionData getSessionData() {
SessionData sd = (SessionData)
jaxrpcContext.getHttpSession().getAttribute(SessionData.SESSION_KEY);
if(sd == null) {
sd = new SessionData();
jaxrpcContext.getHttpSession().setAttribute(SessionData.SESSION_KEY, sd);
}
return sd;
}
...
}
|
Unlike a typical Web browser which handles sessions automatically, the JAX-RPC client does not
participate in a session with the target service endpoint by default. Because of this, the participating clients have to explicitly set a special stub property
(javax.xml.rpc.Stub.SESSION_MAINTAIN_PROPERTY, or,
literally "javax.xml.rpc.session.maintain" ) to true so
that the JAX-RPC client runtime will maintain the session for the invoking client
(see Listing 4). Othewise, the HttpSession
object obtained by the service endpoint is either null or very likely different
across service invocations.
Note that the definition of JAX-RPC client is relative to the service which the client communicates with, and stubs for different services are deemed as different clients. As such, a typical JAX-RPC runtime maintains the session data separately for each individual stub even though stubs may talk with services running at the same back-end server. Therefore, if you write a program to call two different services, you should not expect the session can be maintained across these two service invocations.
Listing 4. Ask the JAX-RPC runtime to maintain the session
javax.xml.rpc.Stub jaxrpcStub = (javax.xml.rpc.Stub) getVendorSpecificStub(); jaxrpcStub._setProperty(javax.xml.rpc.Stub.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE); |
Even though the JAX-RPC-based Web services are stateless in nature, you can exploit a specific service endpoint model such as the servlet-based endpoint to build a stateful Web services application using the session support the servlet container provides. In the meantime, the client is also required to toggle a special flag to notify the JAX-RPC runtime system to maintain the client sessions.
| Name | Size | Download method |
|---|---|---|
| ws-statefulcode.ear | HTTP |
Information about download methods
- Read the Web Services Resource Framework, which defines a family of specifications for accessing stateful resources using Web services.
- Check out "Java API for XML-Based RPC (JAX-RPC) Downloads & Specifications" for links to the JAX-RPC 1.1 specification itself, as well as javadocs, class files, and Sun's JAX-RPC reference implementation.
- Find a number of tips related to Web services programming on developerWorks.
- Access Web services knowledge, tools, and skills with Speed-start Web services, which offers the latest Java-based software development tools and middleware from IBM (trial editions), plus online tutorials and articles, and an online technical forum.
- Browse for books on these and other technical topics.
- Want more? The developerWorks SOA and Web services zone hosts hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop Web services applications.

Ping Wang is one of the developers of IBM's WebSphere Web services engine. Previously, he was a developer for WebSphere System Management and focused on how to manage distributed processes using JMX (Java Management eXtension). You can contact Ping at pacific@us.ibm.com
Comments (Undergoing maintenance)





