Chris's Rants

Friday, December 24, 2004

What's wrong with this picture?

Let me preface this post with a clear statement of intent. I'm about to critique an article written by a couple of my IBM colleagues. It is not my intent to suggest that the article is not well written; it is quite well written. Nor is it my intent to suggest that it is inaccurate in its technical content; technically, it is fine. Rather, what I intend to do is critique the example given in the article, examining why I believe it, and others like it, should not be implemented as a stateful Web service.

The title of the article is: Implement and access stateful Web services using WebSphere Studio, Part 1. The basic jist of the article is to provide the reader with an understanding of how to use the WS-Resource Framework, in conjunction with WS-Addressing, to implement a stateful Web service.

Quoting from the article's introduction:
Web services are generally thought of as being stateless. However, while it is true that Web services are most often accessed over unreliable, stateless protocols such as HTTP, in practice these services can often maintain state or resources on behalf of an individual service requestor or within a particular business context across multiple interactions.
Technically, there's nothing wrong with this statement. A Web service may certainly be designed such that it maintains state on behalf of the client. In fact, many Web services are maintaining some state, usually in a database. Other Web services are purely computational services (e.g. a tax calculator service, a spell checking service, a stock quote service, etc.) which may have some persistent data from which they draw (e.g. tax tables, dictionary, quote feed), but do not expose an interface by which that state can be manipulated by the client. However, simply because a service doesn't expose its state for manipulation, does not necessarily make it stateless. It is the protocol by which it is accessed that makes the service stateful or stateless. If all of the state needed to perform the service is contained within the message requesting the service, then it is considered stateless. If the service provider is required to remember the session state of the requesting client, then it is not stateless.

The article continues:
This article does not debate the merits of the above approaches.
Again, I wish to make it clear that I am not suggesting that the authors should have argued the merits of stateful versus stateless, that was clearly not their intent. My criticism is with the example itself.
We use a simple calculator application as the basis of our samples. First, we implement the calculator for use by RMI/IIOP clients using the J2EE Session Bean Entity Facade pattern. We then show you how the application can be easily exposed to Web services clients via a WSDL interface. Finally, we document the steps necessary to expose the calculator service using the Implied Resource pattern, and show you how to build a client of the calculator service using the approaches outlined in the Web Services Resource Framework (see Resources for a link).

...

Listing 1 proposes an interface for a calculator service that could be consumed by RMI/IIOP clients.

Listing 1. Calculator service interface for remote RMI/IIOP clients
public interface CalculatorService extends Remote { 


public float add(float value1, float value2)
throws java.rmi.RemoteException;
public float sub(float value1, float value2)
throws java.rmi.RemoteException;

}
You can see that the calculator service interface has been designed so that the requestor must input all information necessary to perform an operation; the result is returned as an output of the operation. This type of service is often referred to as being stateless with respect to its interaction with its requestors. This interface design simplifies the job of the service implementer, who can choose to treat each request as an independent interaction.

...

The natural next step in developing this service would be to allocate each user a particular calculator instance. Each requestor could then simply add, subtract, or query the current total from this calculator. A service that maintains information on behalf of a particular requestor is often referred to as being stateful with respect to its interaction with that requestor.

There are many ways in which the service implementer could choose to maintain the calculator total on behalf of a client. It could take advantage of existing context that is available to the service implementation on each request as a means for understanding the calculator state that is to be acted upon.
The article goes on to explain how to implement a stateful Web service using WS-Resource Framework and WS-Addressing, resulting in the following stateful Web service interface:
Listing 9. Implied Resource pattern that allows us to remove the data identifier from the functional interface
public interface CalculatorService extends Remote { 


public javax.xml.soap.SOAPElement
getCalculator(String AcctName)
throws java.rmi.RemoteException;
public float add(float value)
throws java.rmi.RemoteException;
public float sub(float value)
throws java.rmi.RemoteException;
public float getTotal()
throws java.rmi.RemoteException;
}

The article goes on to explain how to implement a stateful Web service using WS-Resource Framework and WS-Addressing. Again, I want to make it clear that I have no problem with the technical content, so I won't bother to quote further from the article.

The problem I wish to call to attention is embodied in this statement in the introduction: "Web services are most often accessed over unreliable, stateless protocols such as HTTP". Therein lies the rub.

Recall fallacy #1 of L. Peter Deutsch's Eight Fallacies of Distributed Computing. Because Web services are typically accessed over a network using HTTP(S), absent addition of either WS-Reliable Messaging (WS-RM) or WS-Atomic Transactions (WS-AT), the implementation of a stateful service will be prone to errors of state resultant from inevitable network failures unless some serious error handling and compensation is built into both the client and service. However, for a service as trivial as the one used in the article, application of either WS-RM or WS-AT would, in the immortal words of Elmer J. Fudd, be like hunting wabbit wiff an ewephant gun: overkill.

If a call to the add operation were to fail, what is the state of the calculator? The service could have processed the add call before the failure, or the request message could have been lost before ever reaching the service. Like Schroedinger's cat, the state of the calculator can't be known.

Granted, the client could compensate for a failed call to the add operation by calling getTotal operation to determine whether the call to the add operation had been processed by the service, but then it would also need to be capable of adding, which would call into question why it was using the service in the first place:-)

I will grant that the example of a calculator service was probably used to keep things simple. However, I think that the authors should have at least made the point that in designing stateful services, one should carefully consider the implications of doing so as regards to reliability. If the service's operations are idempotent, then a failed call to such an operation can simply be retried by the client. The getTotal operation is an example of an idempotent operation on a stateful Web service. However, some form of reliability protocol such as WS-RM or WS-AT needs to be employed to ensure that the non-idempotent operations of a stateful Web service are executed reliably.

In the case of the calculator service example, it would probably have been wiser, and far simpler in the long run, to have designed a stateless Web service.

0 Comments:

Post a Comment

<< Home