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 BankAccountinstance 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 aBankAccount 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 BankAccountproxy, 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. )