Mike,
I’m glad you liked 3 of the 4
proposed simplifications. Regarding the one you didn’t like:
The proposal:
3. Making ServiceReference.setCallbackID(Object id)
illegal and
ServiceReference.getCallbackID() (assuming #2)
return null for
conversational interactions.
Then part of the rationale, and your
response to it, were:
...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.
<MR>I don’t know... Claiming we are baby-killers seems a
bit severe doesn’t it :-) </MR>
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>
<MR>Actually my point on BPEL
correlation is a little more subtle. Having to use correlation to get to the
right process instance is indeed too much of a pain. The system should be able
to do that. However, when you have a complex process and you need to get to
the right place within that process, then correlation is OK, and in fact the
SCA BPEL spec makes it clear that BPEL correlations can and should continue to
be used for this. Because this is a less-common complex case, it is OK to
require some complication in the solution.
The situation is analogous for Java. The infrastructure
should be able to route to the right client instance, based on the conversation
that is taking place. If you need finer-grained correlation, that is up to
you.
Also, it would be difficult or impossible
for the system to make any useful guarantees about which callback ID will be
received for a conversational interaction. Imagine this case (pseudocode):
{
setCallbackID(“1”)
callService()
setCallbackID(“2”)
callService()
}
receiveCallback() {
getCallbackID();
-- what does this return?
}
When multiple callback IDs are set within
a single conversation, there is nothing to guarantee that the service provider
will keep track of all of the outstanding callback IDs (“1” and “2”
in this case) and use the most appropriate one when it is invoking a callback.
Creating such an ability to automatically maintain a set of outstanding
callback IDs would be too complex for the value it would provide.
Michael
From: Mike
Edwards [mailto:mike_edwards@uk.ibm.com]
Sent: Wednesday, February 13, 2008
5:24 AM
To: OASIS Java
Subject: 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: mike_edwards@uk.ibm.com
Jim Marino <jmarino@bea.com>
12/02/2008 18:23
|
To
|
OASIS Java <sca-j@lists.oasis-open.org>
|
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