Re: [sca-j] Java Callback Simplification Proposal

From
Mike Edwards <>
Date
2008-02-13T10:24:55+00:00
ID
Thread
Re: [sca-j] Java Callback Simplification Proposal
Jim,

Thanks for this detailed proposal.

I've got a few concerns, that I can
summarize simply as "the baby being thrown out with the bathwater"

- ie some capabilities that are actually
quite important seem to get chopped in the name of simplicity.

I'm left feeling that callbacks in particular
are no longer of any use once the proposals are accepted.

Let me try to express what I see as
the problems in inline comments as <mje>...</mje>

Yours,  Mike.

Strategist - Emerging Technologies, SCA & SDO.

Co Chair OASIS SCA Assembly TC.

IBM Hursley Park, Mail Point 146, Winchester, SO21 2JN, Great Britain.

Phone & FAX: +44-1962-818014    Mobile: +44-7802-467431  

Email:  

Jim Marino <>

12/02/2008 18:23

To

OASIS Java <>

cc

Subject

[sca-j] Java Callback Simplification
Proposal

All,

Bellow is a proposal from BEA to simplify callback mechanisms in the  

Java C&I specifications. I will work on the appropriate steps of  

getting this into a JIRA so that it can be tracked.

Thanks,

Jim

This proposal aims to simplify using asynchronous communication in  

the SCA Java programming model by:

1. Eliminating callback objects.

    - Removing ServiceReference.get/setCallback()

<mje>So this implies
the client MUST implement the callback I/F</mje>

2. Removing the ability for service providers to get callback IDs.

    - Moving CallableReference getCallbackID() to ServiceReference)

<mje>.+1 </mje>

<mje>There is one
interesting argument to follow from this.  It is possible to 

take the view that callbackID
is only of interest to the client, while conversationID

is only really of use to
the provider.  Each is being used to pick out state of

some kind, but at opposite
ends of the communication. So perhaps we can

eliminate the client having
access to the conversation ID?

It would be nice to coalesce
the 2 IDs,  The problem is that they have completely

different lifecycles.  The
conversationID has some fixed span dictated by the

form of the forward call
interface, with specific starting and ending operations.

The callback ID has an
indeterminate span, always starting with one forward

call, but with an undetermined
number and type of callback operations 

being included in its span.
Logically it needs to change for each subsequent

forward call.

I'm now really heading
off into the weeds, but it occurs to me that there is a 

relationship of the callback
ID to the concept of "Future" that is used in the Java

concurrency packages.  There,
the Future represents the asychronous operation

that is taking place, and
can be used to feed back results. The Future is handed

back to the "client"
application on the invocation of the forward "service" invocation.

Today, Futures only handle
one-shot pieces of asychronous work, with a single

"response" message.
 However, you could conceive of stretching this, to permit

something you might call
a "CallbackFuture" - which would represent an asynchronous

process with a continuing
life and an arbitrary number of "response" messages.

The nasty thing about this
is that with our current callback design there is no

obvious end to the life
of a CallbackFuture - in other words, the callback interface

does not define the equivalent
of an "endsConversation" which indicates completion

of the work of the asynchronous
service.  Today, the "end" of the callbacks must

be defined in metadata
outside the interface.  Perhaps we need to fix that,

but it will not be easy.</mje>

3. Saying callback IDs are irrelevant in conversations.

    - Making ServiceReference.setCallbackID(Object id) illegal
and

      ServiceReference.getCallbackID() (assuming #2) return
null for

      conversational interactions.

<mje>Why does having
a conversation enable this to be done?

The callback ID I thought
allowed a client to mark a service invocation in

a way that callbacks made
to the client carried the same ID and that

this enables the client
to establish which original request caused a

given response.  

Conversation ID does not
do this at all, unless I am mistaken, since

while callback ID can change
from one invocation to the next, conversation ID

stays the same for the
whole of a conversation.  Thus conversation ID is

useless for distinguishing
one callback from another.</mje>

4. Removing the distinction between stateless and conversational

    callback interfaces.

     - Removing the ability to specify conversational on callback

       Interfaces.

<mje>+1</mje>

By simplification, we mean as a primarily reducing the number of  

concepts and APIs a developer must understand to program  

asynchronous  services. This will entail some reduction in  

capability. However,  this reduction, we argue, affects edge-cases
 

that can be accommodated through alternative techniques. A secondary  

aspect of simplification concerns implementation. By removing the  

requirement for runtimes to provide infrastructure for  handling edge
 

cases that can be accommodated through relatively simple application  

programming techniques,implementing callback capabilities becomes  

fairly straightforward.

<mje>Unfortunately,
unless I'm mistaken, some rather central use cases have been

trashed too.</mje>

[RATIONAL]

The rational for proposed items is dealt with individually in this  

section.

1. ServiceReference.setCallback(Object object) and  

ServiceReference.getCallback()

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

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

<mje>+1</mje>

This API exists as a mechanism to route callbacks to instances other  

than an instance of the client component making a forward invocation.  

This provides two capabilities.  Clients do not have to implement
a  

callback interface. The API also allows clients to instruct the  

runtime to perform callback dispatching for stateless interactions  

that execute concurrently. A common example of this is inventory  

check. A client component needs to perform an inventory check for  

multiple line items. As an efficiency, it written to invoke the same

inventory service using a non-blocking call multiple times. For each  

invocation, it wishes to dispatch the associated callback to a  

different handler instance it creates.  For example:

ServiceReference<InventoryService> serviceReference = ..

for (LineItem item: purchaseOrder.getLineItems()) {

     CallbackService handler = new CallbackServiceImpl();

     serviceReference.setCallback(handler)

     serviceReference.getService().checkInventory(item);

}

This can be done using the CallableReference.getCallbackID():

// code that conducts the forward invoke:

ServiceReference<InventoryService> serviceReference = ..

for (LineItem item: purchaseOrder.getLineItems()) {

     String id = // generate or assign the callback ID

     // store the callback id and whatever information the callback
 

needs

     cache.put(id, handler);

     serviceReference.getService().checkInventory(item);

}

Callback processing can either be done directly by a component  

implementation instance or delegated to CallbackServiceImpl as shown  

below:

// code in the same class that handles the callback:

public void onCallback(InventoryStatus status) {

     String id = requestContext.getServiceReference().getCallbackID();

     CallbackInfo info = .. // retrieve the stored callback

information by using the callback id

     CallbackService handler = new CallbackServiceImpl(info);

     handler.onCallback(status);

}

Some advantages to eliminating get/set/Callback() are:

a. Reduces the number of concepts and APIs a developer will be  

presented with without affecting common functionality. In other  

words, this API is primarily used for edge-cases and removing it  

simplifies the common case.

b. Application migrations and versioning are easier using the   

alternative approach. By using an object instance, runtime  

implementations would be responsible for handling class versioning

for in-process interactions. By avoiding serialization and the use of  

a specific classes, and instead storing callback data,  

CallbackServiceImpl can be versioned and substituted for callbacks  

that have not yet occurred.

c. Runtime performance characteristics are likely to improve. For  

cases where the client is stateless, routing to the specific instance  

set through setCallback() requires that the callback be routed to the  

specific JVM where the instance is hosted. Eliminating routing to a  

particular instance allows the callback to potentially be sent to any  

JVM where the client component is hosted.

d. Eliminates the need for runtime implementations to manage garbage  

collection of callback objects. For example, if a callback is never  

made, the runtime at some point will need to remove the object from  

storage or memory.

2. Moving CallableReference.getCallbackID() to ServiceReference

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

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

<mje>+1</mje>

We propose removing getCallbackID() from access by service providers  

as it is cannot be used for correlation in third-party components  

except when the third-party is configured with a callback to the same  

client component. For example in the stateless case:

A---------B--------C

The only way C can callback to A is either by calling back B or  

having B pass a CallableReference to C.  The callback ID is not  

sufficient, in itself, to be used by arbitrary code to send a message  

that qualifies as a callback in this bidirectional exchange.  For
 

example, if B has clients other than A, the callback ID doesn’t have  

the information to tell which client it is for.

Moving CallableReference.getCallbackID() to ServiceReference   

simplifies the Java programming model by:

a. Eliminating an API that can only be used in very particular  

circumstances.

b. Removing the need for a runtime implementation to create and  

maintain a distributed domain-wide mapping of callback ids to  

callback endpoints. Note that routing information cannot be encoded  

in the callback id as it can be set by the application.

3. Making ServiceReference.setCallbackID(Object id) illegal and  

ServiceReference.getCallbackID() (assuming #2) return null for  

conversational interactions.

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

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

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

Having both callback ids and conversation ids for bi-directional  

conversational wires is confusing and not needed as the conversation  

id will be used for correlation. 

<mje>This is what
I challenge - it isn't true if you need to correlate callback responses

to individual requests.
 Conversation ID is necessarily the same for all the forward

invocations in a conversation.
 This then is useless for distinguishing between 

callback messages resulting
from different forward invocations.

In fact, I argue that conversationID
is almost useless for the client - it's really a 

provider-defined thing
useful for the provider to access its state data.</mje>

Sometimes a client may wish to  

correlate callback invocations using the callback id. For  

conversational callbacks, correlation using the callback id is  

limited. Since conversations are serial between a particular client  

instance and a provider instance, the additional correlation that may  

be needed is between different invocations to the provider within the  

same conversation. In other words, conversations by nature correlate  

invocations between a client and provider instance. If finer-grained  

correlation is needed such as between multiple invocations in the  

same conversation, correlation data can be included as part of the  

service operation data (e.g. “line item number” can be passed as a  

parameter in the example above).

<mje>THIS is where
I hear the baby screaming as it flies out with the bathwater.

IF you really believe that,
then there is no need for a callback ID ever.  All you

do is use correlation data
in the messages themselves.  I suggested this to

Michael Rowley not so long
ago, with the model of BPEL correlation in mind.  He

was of the opinion that
the BPEL correlation approach was a failure and not

to be used as a model for
SCA.

There is a good argument
to be made for a system managed correlation

mechanism in that it simplifies
the life of the programmer.  Forcing the use of

correlation data in the
message may well have the consequence of distorting

the form of the messages,
since they now *HAVE* to contain data fields that

are "uniquely identifying"
- and this must be done for all callback messages.

</mje>

This simplifies the Java programming model by clarifying the  

relationship between callback and conversation ids.

4. Removing the ability to specify stateless or conversational  

callback service contracts

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

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

<mje>+1</mje>

We propose wires be either conversational or stateless in both  

directions and that it be specified as part of the forward service  

contract. In other words, @Conversational cannot be specified on the  

callback interface definition.  We don't believe having a stateless
 

callback for a stateful forward invocation and vice versa makes much  

sense.

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

To unsubscribe from this mail list, you must leave the OASIS TC that

generates this mail.  You may a link to this group and all your TCs
in OASIS

at:

https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php

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