Skip to main content

Stateful web service with JAX-WS RI 2.1 EA2

Posted by kohsuke on October 24, 2006 at 12:19 PM PDT

One of the additions in the JAX-WS RI EA2 is the support of stateful web services by using WS-Addressing underneath.

Normally, the JAX-WS RI only creates one instance of your service class, and have it handle all incoming requests concurrently. This effectively takes you back to pre-OO programming, as you will not be able to make use of instance fields at all — it's as if all your methods are static. The problem with that is that if the rest of your application is modeled in OO, this mismatch becomes painful. It would be much nicer if you can make it OO all the way, like you do with RMI, where you can export "objects". The stateful web service support brings you that. On the wire, it uses WS-Addressing standard, so it's fully interoperable.

Now, how do you use it? First, your class has to have @Stateful annotation, like this. In this version you'd also need to explicitly set @Addressing to enable WS-Addressing, but I'm going to change that so you won't need it.

@Stateful @WebService @Addressing
class BankAccount {
    protected final int id;
    private int balance;
   
    Account(int id) { this.id = id; }
   
    @WebMethod
    public synchronized void deposit(int amount) { balance+=amount; }

    // either via a public static field
   
    public static StatefulWebServiceManager<BankAccount> manager;
   

    // ... or  via a public static method (the method name could be anything)
   
    public static void setManager(StatefulWebServiceManager<BankAccount> manager) {
       ...
    }
   


}

Your class would also have StatefulWebServiceManager static field or method, where the JAX-WS RI injects an instance. You'll talk with the manager to get objects exported.

The other thing to note is that the BankAccount instance is now completely stateful. Each instance represents a specific bank account denoted by ID, and incoming requests are dispatched to the right instance (although you still need to synchronize methods if you expect concurrent invocations to the same object.)

The following normal stateless service shows how you can send a "remote reference" to a BankAccount object to the client:

@WebService
class Bank { // this is ordinary stateless service
    @WebMethod
    public synchronized W3CEndpointReference login(int accountId, int pin) {
        if(!checkPin(pin))
            throw new AuthenticationFailedException("invalid pin");
        BankAccount acc = new BankAccount(accountId);
        return BankAccount.manager.export(acc);
    }
}

The key here is the export operation. It takes a reference of a BankAccount object, then creates an "endpoint reference" object, which is really a remote reference to this specific bank account. In this example, it then sends it back to the client.

The client code can look like this:

BankAccount account1 = accountService.getPort(bankServicePort.getAccount(1), Account.class);
BankAccount account2 = accountService.getPort(bankServicePort.getAccount(2), Account.class);

account1.deposit(100);
account2.deposit(-100);

Admittedly it's bit ugly to get to the BankAccount proxy, but two account proxies created this way are connected to two different server-side BankAccount objects, so things are much object-oriented now.

The obvious improvement to this is to hook this up with Java Persistence API, so that you can create a remote reference to a persisted object. In that way, you can create a durable remote reference that other systems can use to talk to your objects. So please expect more improvements in this area in the future.

(This is a follow up to my earlier post about the state support in the JAX-WS RI. )

Related Topics >>

Comments

Stateful Service

Have you been able to deploy this code in OracleWeb Logic Server

stateful definition

Actually, what is the proper definition of stateful web service? You said that this was the proper way to implement stateful web service, but I'm still not understand why this method was classified as stateful web service, but, other method, e.g. by using httpsessionscope, is not. Thanks very much.