OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

sca-j message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: Re: [sca-j] Another early morning brainstorm - conversations revisited


Hi,

I'm sorry I was unable to attend the second half of Wednesday's meeting so want to caveat my response by saying I may be missing some of the discussion context. I'll break down my response into several parts.

1. Question on CallableReference

I think it would be helpful if all of the code examples were first laid out, particularly since I don't think the examples can be made to compile (I'm probably missing something here). One of the places I'm having trouble is with the genericized version of CallableReference, which I assume takes the forward service interface as a parameter type. So, if OrderService is defined as:

public interface OrderService { 
    public void orderApples(int quantity, CallableReference<OrderService>); 
    public void orderPlums(int quantity, CallableReference<OrderService>); 
} 

I'm having trouble seeing how this can work:

public void orderApples(int quantity, CallableReference<OrderService> myClient) { 
    boolean success = placeOrder("apples", quantity); 
    myClient.getCallback().reportResult(success); 
} 

without adding a parameter type to CallableReference taking the callback interface, as in CallableReference<FORWARD, CALLBACK>. If this were added, I think the programming model would be very cumbersome and would require people to declare a forward-only CallableReference as CallableReference<SomeInterface, Void>. I may be missing something really basic here. 

I'm also really confused by the following: 

CallableReference<OrderService> myConversation = myService.startNewOrder(); // returns an ID for the entire fruit order 
CallableReference<OrderService> myAppleOrder = myConversation.createCallbackReference(); // myAppleOrder is linked to myConversation 
myAppleOrder.orderApples(12); // the infrastructure sends IDs for both myConversation and myAppleOrder 
CallableReference<OrderService> myPlumOrder = myConversation.createCallbackReference(); // myPlumOrder is linked to myConversation 
myPlumOrder.orderPlums(6); // the infrastructure sends IDs for both myConversation and myPlumOrder 

Specifically:

- I don't think "myAppleOrder.orderApples(12)" will compile
- What is the purpose of myAppleOrder and myPlumOrder? Where would these be used?


2. Clarification on service operation signatures

I'm unclear if by the following the proposal intends to require use of CallableReference for conversational interactions:

A simple extension to the model already proposed can solve both these problems.  A conversation would be initiated by the service creating a CallableReference and returning it to the client.  This CallableReference contains an identity for the conversation.  This client then makes multiple calls through this CallableReference instance.  Because these calls all carry the same identity, a conversation-scoped service will dispatch all of them to the same instance. 

I'm assuming this is just for illustrative purposes and it would be possible for a conversation to be initiated in response to the following client code, which does not use the CallableReference API:

public class OrderClient ... {

@Reference
protected OrderService service;

public void doIt() {
service.orderApples(...);
service.orderPlums(...); // routed to the same target instance
}


Is this correct?

3. Clarification on how a conversation can be ended

The proposal states:

This combination of having the service initiate a conversation and the client decide when to end it provides the correct combination of semantics and resolves Anish's first concern.. 

Would it still be possible to have the forward conversation end as a result of a callback as in onFullfilled(..) being called on the following interface, without the client having to do something specific in response?

public interface OrderCallback {
@EndsConversation
void onFullfilled(..t);

}

4. Clarification on @Callback

Could the following example: 

@Context 
RequestContext requestContext; 

public void orderApples(int quantity) { 
    boolean success = placeOrder("apples", quantity); 
    requestContext.getCallback().reportResult(success); 
} 

be re-implemented as:

@Callback 
protected OrderCallback callback; 

public void orderApples(int quantity) { 
    boolean success = placeOrder("apples", quantity); 
    callback.reportResult(success); 


The re-written version (which can be done with the existing calback mechanisms) is IMO less complex and much easier to test.

---------------- 

As a general comment, I consider it an anti-pattern to put infrastructure-specific types in service contracts (e.g. CallableReference) since it ties a priori both provider and client implementations to specific infrastructure choices and makes testing much more difficult (APIs have to be mocked out). I'm almost tempted to say CallableReferences  should almost never be passed around as part of service signatures (use strong types and pass proxies instead). I'm sure that may be controversial.

Thanks,
Jim

On Jul 18, 2008, at 5:45 AM, Simon Nash wrote:


In Wednesday's discussion at the F2F, Anish made the point that using the proposed CallableReference model to handle conversations has the problem that it requires the client to create the "conversation ID", but this responsibility should be with the server.  Anish was also concerned that combining the "callback ID" and "conversation ID" concepts changes the callback programming model depending whether or not a conversation is in progress.

A simple extension to the model already proposed can solve both these problems.  A conversation would be initiated by the service creating a CallableReference and returning it to the client.  This CallableReference contains an identity for the conversation.  This client then makes multiple calls through this CallableReference instance.  Because these calls all carry the same identity, a conversation-scoped service will dispatch all of them to the same instance.

This combination of having the service initiate a conversation and the client decide when to end it provides the correct combination of semantics and resolves Anish's first concern..

To resolve Anish's second concern, a bit more programming or an extra mechanism is needed.  If the client is using a conversational CallableReference that was created by the service, it can't add its own correlation ID to this CallableReference because CallableReferences are immutable.  If it needs this per-call correlation, it would need to create a new CallableReference and pass this on the call.  One way to do this would be to use business data.  The client code would look like this:

CallableReference<OrderService> myConversation = myService.startNewOrder(); // returns an ID for the entire fruit order
CallableReference<OrderService> myAppleOrder = myConversation.createCallableReference(); // create an ID for the apple order request
myConversation.orderApples(12, myAppleOrder); // the infrastructure sends an ID for myConversation
CallableReference<OrderService> myPlumOrder = myConversation.createCallableReference(); // create an ID for the plum order request
myConversation.orderPlums(6, myPlumOrder); // the infrastructure sends an ID for myConversation

The service interface looks like this:

public interface OrderService {
    public void orderApples(int quantity, CallableReference<OrderService>);
    public void orderPlums(int quantity, CallableReference<OrderService>);
}

The service provider code looks like this:

public void orderApples(int quantity, CallableReference<OrderService> myClient) {
    boolean success = placeOrder("apples", quantity);
    myClient.getCallback().reportResult(success);
}

This works, but it makes the business interface rather cumbersome, and the business interface and service provider programming model are different from the non-conversational case.  If we want to optimize the business interface for this case further, and make the service provider programming model the same for the conversational and non-conversational cases, we could allow CallableReferences to be linked together so that the CallableReference for the callback delegates its forward call identity to a second CallableReference for the forward call.  Using this approach, the client code would look like this:

CallableReference<OrderService> myConversation = myService.startNewOrder(); // returns an ID for the entire fruit order
CallableReference<OrderService> myAppleOrder = myConversation.createCallbackReference(); // myAppleOrder is linked to myConversation
myAppleOrder.orderApples(12); // the infrastructure sends IDs for both myConversation and myAppleOrder
CallableReference<OrderService> myPlumOrder = myConversation.createCallbackReference(); // myPlumOrder is linked to myConversation
myPlumOrder.orderPlums(6); // the infrastructure sends IDs for both myConversation and myPlumOrder

The service interface now looks like this:

public interface OrderService {
    public void orderApples(int quantity);
    public void orderPlums(int quantity);
}

The service provider code is now identical to the non-conversational case and looks like this:

@Context
RequestContext requestContext;

public void orderApples(int quantity) {
    boolean success = placeOrder("apples", quantity);
    requestContext.getCallback().reportResult(success);
}


    Simon

Simon C. Nash, IBM Distinguished Engineer
Member of the IBM Academy of Technology
Tel. +44-1962-815156  Fax +44-1962-818999






Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number 741598.
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6 3AU









[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]