Note that BEA is not the only company with
experience treating service callbacks in this way. Take a look at an
example “duplex
contract” in WCF. Note the lack of any correlation data in the
callback parameters.
Michael
From: Michael
Rowley [mailto:mrowley@bea.com]
Sent: Thursday, April 10, 2008
4:26 PM
To: Simon Nash;
sca-j@lists.oasis-open.org
Subject: RE: [sca-j] ISSUE 25 -
Callback Simplification
Simon,
Looking at code is indeed
an excellent way to handle this. Here is a bidirectional interface pair
that I think represents the most common case:
@Callback(OrderCallback.class)
public interface
OrderService {
void placeOrder(Order order);
}
public interface
OrderCallback {
void confirm();
}
Here is a conversational
client. I believe this client can be written using either of our
proposals:
@Scope(CONVERSATIONAL)
public class Client
implements OrderCallback {
Order
myOrder;
@Reference
OrderService orderService;
void
buy(Order order) {
myOrder = order;
orderProcessor.placeOrder(orderData);
}
void
confirm() {
myOrder.setConfirmed(true);
}
}
The above client is, I
believe, the simplest and most common case. I think it is much less
common that there will be multiple outstanding callbacks, but if there were,
the client might need to maintain a Map of, for example, items ordered and
confirmations for each item (assuming there is a callback for each).
However, it would still be in the context of the original purchase order
that had been made.
Nonetheless, it should be
possible (although not necessarily easy, given its less frequent use) that
someone be able to create a client for this service that is stateless.
This stateless client would be responsible for the storage and
correlation work that a conversational component would have done for him.
Thus the stateless client would look like this (using the current API, so
as not to confuse things too much):
@Scope(STATELESS)
public class Client
implements OrderCallback {
@Reference
ServiceReference<OrderService> orderService;
@Context
RequestContext requestContext;
PersistenceHelper persistenceHelper; // a way of skipping junk I don’t
want to show.
void
buy(Order order) {
orderService.getService().placeOrder(order);
Object orderID =
orderProcessor.getCallbackID();
persistenceHelper.persist(orderID,
order);
}
void
confirm() {
Object orderID = requestContext.getCallbackID();
Order order = persistenceHelper.find(orderID);
order.setConfirmed(true);
persistenceHelper.store(orderID, order);
}
}
This is leaving out all
the technical junk that would also need to be done in order to set up the
connection to the persistence context, dealing with transactions (even if
declaratively), etc. All of the stuff that is done for you when you have
a conversational client.
SUMMARY:
In both of our approaches
people can, and therefore would, create the simple code in the conversational-scoped
client of the first example. However, in your approach, it would then be
impossible to use that service from the stateless client, such as I show in the
second example. Because of this, people would unwittingly write services
that could only be used by conversational clients.
I do understand that you
would advise them _not_ to create
interfaces such as the one I have here, and would tell them that they _should_ always pass around enough
information so that they could create a stateless client even without help from
a system generated callbackID. However, since in the
conversational-scoped case that extra information would not be needed, I
don’t think people would do it.
Michael
From: Simon
Nash [mailto:NASH@uk.ibm.com]
Sent: Thursday, April 10, 2008
10:42 AM
To: sca-j@lists.oasis-open.org
Subject: RE: [sca-j] ISSUE 25 -
Callback Simplification
Michael,
I
think we're talking about example 2 here (stateless client and stateful
callback).
The bidirectional
interface provided by C should be usable by clients of all different scopes.
For a stateless scoped client, the business data must be present or else
the client cannot identify the order being confirmed. I'm not sure how
your proposal would address this requirement. The automatic correlation
works only in very limited cases (conversation scoped client with a single
outbound request in progress at any one time). In all other cases,
business data must be used for the correlation. It's far simpler to pass
explicit business data on the service call in every case, with a consistent
programming model, than to have an automated "convenience" feature
for a single relatively uncommon case and a complex programming model that uses
special APIs to handle all other cases.
Can
you illustrate the code needed on the client and provider sides to implement
example 2 with your proposal for a) a stateless client and b) a conversational
client? The interface and provider code should be the same in both cases.
I think this will make the complexity issues clear.
Simon
Simon C. Nash, IBM Distinguished Engineer
Member of the IBM
Academy of Technology
Tel. +44-1962-815156 Fax +44-1962-818999
"Michael Rowley"
<mrowley@bea.com>
08/04/2008
21:38
|
To
|
Simon Nash/UK/IBM@IBMGB
|
cc
|
<sca-j@lists.oasis-open.org>
|
Subject
|
RE: [sca-j] ISSUE 25 - Callback Simplification
|
|
Simon,
I am certainly willing to give up any automatic correlation when
there may be multiple simultaneous outstanding callbacks. In that case,
use business data.
However, for the common case where there is only one
outstanding callback for a specific client, then your approach already allows
the client to know what the callback is talking about without passing any
correlation information in the business data. This is because your
approach routes the callback to the right client instance.
I think this is good. We should encourage it.
However, in the unfortunate event that someone can’t use a
conversational-scoped client, they should still be able to use the
bi-directional service without having to ask the service provider to change its
interface. Admittedly, the stateless client will have to implement many
of the steps that you list below, but that is the price for being
non-conversational.
I also believe that if we followed your suggestion, then no
matter what we say, people just won’t send unneeded correlation information
as business data when they know that the callback is going to be sent to the
right place. They won’t think: “Oh, just in case I ever have
a stateless client, I better put this extra data into the business data.”
Instead, they will just leave out the data, with the unintended
consequence being that they’ve limited their clients to being only those
that use a conversational scope. That would be bad.
Michael
From: Simon Nash
[mailto:NASH@uk.ibm.com]
Sent: Thursday, April 03, 2008 12:13 PM
To: Michael Rowley
Cc: sca-j@lists.oasis-open.org
Subject: RE: [sca-j] ISSUE 25 - Callback Simplification
There's a basic problem with this approach. Whether or not B has
conversational scope depends on its interactions with A. In a single A to
B conversation, the same conversational instance of B might place 5 orders with
C. Using the A to B conversation ID to identify the order that was placed
is therefore never safe, even if B is conversational.
The only way this approach could work is if B were to generate a new
"callback conversation ID" for every request that it sends to C.
This would be different from any regular conversation ID that B may be
sending to C as part of a B to C conversation. Here are the steps that
would need to be followed.
1. B generates a new "callback conversation ID" and associates it
with its reference for C. This needs to happen before any calls to C are
made.
2. An API needs to be defined to allow B to get this "callback conversation
ID" before it makes the placeOrder() call to C. B stores the
"callback conversation ID" and associates it with the order it is
placing.
3. B makes a placeOrder() call to C.
4. The SCA infrastructure transmits the "callback conversation ID"
from B to C with the placeOrder() call.
5. C stores the "callback conversation ID" in the callback reference
so that it can be returned to B in any callbacks.
6. C makes a callback to B.
7. The SCA infrastructure transmits the "callback conversation ID"
from C to B with the callback.
8. An API needs to be defined to allow B to get this "callback
conversation ID" when the callback is executing. This ID is
different from the conversation ID that's active for the A to B conversation.
All of the above are not needed if the correlation information is passed as
business data, which is a much simpler approach.
I considered this approach when I was trying to come up with a good definition
of conversational callback interfaces between the 3/20 and 3/27 calls, but I rejected
it because I did not believe that the value justified the complexity.
Simon
Simon C. Nash, IBM Distinguished Engineer
Member of the IBM
Academy of Technology
Tel. +44-1962-815156 Fax +44-1962-818999
"Michael Rowley" <mnrowley@gmail.com>
03/04/2008
15:40
Please respond
to
mrowley@bea.com
|
|
To
|
Simon Nash/UK/IBM@IBMGB, sca-j@lists.oasis-open.org
|
cc
|
|
Subject
|
RE: [sca-j] ISSUE 25 - Callback Simplification
|
|
I like the fact that, in Simon's
model, callbacks always go back to the instance that made the outbound call.
However, it looks like he does not take advantage of that fact in the
interfaces of the examples that he created. For example, he has the
following:
@Callback(OrderCallback.class)
public interface Order {
void
placeOrder(String orderID, String orderData);
}
public interface OrderCallback {
void
confirm(String orderID);
void
update(String orderID, String status);
}
However, since you know
that the order callback goes back to the right instance, you should be able to
define the callback interface as follows:
public interface OrderCallback {
void
confirm();
void
update(String status);
}
In Simon's model this
should be possible, but there is a catch. If the callback interface is
defined this way, the client has to use a conversational scope. If the
client is stateless or composite scoped, then the routing of the callback to the
right instance doesn't say anything useful about what is being confirmed.
I would like to enable
this style of callback interface irrespective of the scope of the client.
As with Simon's approach, if the client is conversational scoped, then
the client is especially simple and does not have to do any correlation at all.
However, if the client needs to use some other scope, for whatever
reason, then the service with the callback can still be used. However, it
just needs to get the callback ID (or conversation ID) that is associated with
the callback in order to determine what the callback is talking about.
Michael
From: Simon
Nash [mailto:NASH@uk.ibm.com]
Sent: Thursday, March 27, 2008 11:47 AM
To: sca-j@lists.oasis-open.org
Subject: Re: [sca-j] ISSUE 25 - Callback Simplification
There's an update to this proposal at
http://www.oasis-open.org/apps/org/workgroup/sca-j/download.php/27733/JAVA-25-Proposal-2.doc
This version removes conversational callbacks as all my attempts to define
these involve more complexity than is justified by the functional value of this
capability.
Simon
Simon C. Nash, IBM Distinguished Engineer
Member of the IBM
Academy of Technology
Tel. +44-1962-815156 Fax +44-1962-818999
Simon Nash/UK/IBM@IBMGB
20/03/2008
11:01
|
|
Last week I took an action to produce a written up proposal for callback
simplification by today. I have uploaded this to the document repository
as
http://www.oasis-open.org/apps/org/workgroup/sca-j/download.php/27649/JAVA-25-Proposal.doc.
The content of this proposal corresponds to the "Callback
Simplification" section of the proposal sent out by Michael R, and does
not address the changes proposed in the "API Simplification" section.
I think it is best to have these discussions separately.
This proposal corresponds to what I was describing at the sca-j F2F with two
changes / additions:
1. Outstanding callbacks don't pin conversational objects after the
conversation's creator has ended the conversation.
2. In all cases, the caller of a bidirectional interface creates the callback
EPR that will be used (including any reference parameters needed).
I believe the issues that still need to be discussed and resolved are as
follows:
a) Should all 4 combinations of conversational and non-conversational forward
and callback interfaces be allowed, or only 2 of these?
b) Should the callback interface used to make callbacks to a conversation-scoped
component be marked as conversational?
c) Should each forward request within a conversation generate a unique ID that
is not part of business data and is returned with the callback?
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
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
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
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