Friday, February 29, 2008

Modelling Service Verbs as Java Classes

OK, so this is probably just an intellectual exercise for now, but someone may find a way to make it practical. Read on.

I've been going on in the recent past about how Services need to be verbs that make sense from a service consumer's point of view. Let's say we can articulate such verbs that reflect our domain from the outside looking in (the Viewpoint Flip of service-orientation). In other words, we manage to model the Service Interface quite independently of the Domain Objects.

How do we implement the verbs in this Service Interface? If we use a language like Java which is noun-oriented, that's going to be hard, as this hilarious article illustrates so well.

I propose we use the features of Java 5 to promote our service methods to the level of first class Java entities, i.e., classes. How do we do that?

Look at this example:

import java.text.DecimalFormat;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutionException;

// It's a noun! It's a verb! It's a Callable!
//
public class GetStockQuote implements Callable
{
private String stockCode;

// Constructor
//
public GetStockQuote( String _stockCode ) { stockCode = _stockCode; }

// Actual method, but it's effectively hidden and only implicitly called.
//
public String call()
{
DecimalFormat decimalFormat = new DecimalFormat( "0.00" );

// In a real system, use the stock code to look up the stock price.
// Here, just generate a random price.
//
double stockPrice = Math.random() * 100;
return decimalFormat.format( stockPrice );
}

// Test the "service".
//
public static void main( String[] _args )
{
String stockCode = "JAVA";
String stockPrice = null;

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit( new GetStockQuote( stockCode ) );

try
{
stockPrice = future.get();
executorService.shutdown();
}
catch ( InterruptedException ie )
{
System.out.println( ie.toString() );
}
catch ( ExecutionException ee )
{
System.out.println( ee.toString() );
}

System.out.println( "The price of " + stockCode + " is " + stockPrice );
}
}

As we can see, the Future interface makes the call asynchronous. We could have performed the service in one line:

stockPrice = executorService.submit( new GetStockQuote( stockCode ) ).get();

That would have been a synchronous call.

It's a bit strange to see a verb like GetStockQuote strutting about as a class. In fact, it seems as wrong as those horrible C# method names with initial capitals ;-). But hey, that's the only way King Java will allow verbs to walk around by themselves without a noun chaperone. They've got to become nouns themselves, and the set of classes and interfaces in the java.util.concurrent package makes this passably easy to do.

Now that we've done this, we don't mind too much if someone annotates this verb "class" and generates a SOAP interface and a WSDL description from it. We have already performed the viewpoint flip (in Java), and since we believe that operation is the distinguishing feature of SOA, we are confident that even auto-generating a Web Services interface from this viewpoint-flipped class will not curse it with RPC semantics. It will be a true service.

The reasons why this still isn't going to be easy to turn into SOAP services is this: GetStockQuote will be the WSDL name for the service all right, but what will the operation be called? (The "service" in WSDL is just the wrapper for a number of "operations", which correspond to object methods.) I think "call()" is a rather weak name for the operation, but I guess it corresponds to "processThis()", which is the "uniform interface" of the SOAP messaging model (MEST).

More practically, the Callable mechanism requires the call to be made in two passes. The first pass involves calling the constructor with the parameters to the service. The second pass involves calling the "call()" method (indirectly) by submitting the class to an executor. How would that mechanism translate to a WSDL definition? I must confess I'm stumped there.

Anyway, this is my rough idea for a way to accommodate the automatic interface generation approach provided by SOA tools today without compromising the spirit of SOA by embracing RPC semantics. I'm sure some refinements to this idea will be proposed by wiser heads than mine.

No comments: