I was wondering if it's possible to cancel an undergoing RPC, even to
make it fail on purpose so as to definately _not_ receive a
success/fail after the cancellation.
G.
...........................
asyncInterface.method(new AsyncCallback() {
public void onSuccess(Object result) {
if(!cancelled){
........................
}
}
public void onFailure(){
if(!cancelled) {
....................
}
}
});
cancelled = true;
The only way I can think of to avoid reception of a result (success or
fail) on the client side is to close the page ;-). The server side
logic will still be executed. But if you're only concerned about the
client side, Slava's solution will work.
Of course, the network communication is far from participating in a
transaction thus I wouldn't even attempt on 'rolling back' server
actions. I am more interested in the client side here and yes, though
Slava's solution works... it's cumbersome, although the only possible I
see in the absence of something like Window.cancelPendingRPC()... or
even nicer, if the RPC invocation returned a handle which one then can
cancel.
I try to see this similar to canceling timer events with the
window.setTimeout() in javascript: I can call window.clearTimeout() and
never receive the (now cancelled) call, while in the solution provided
in the previous post, I still receive the call - but I must know now
that I have to discard it.
This is in general not easy at all, because the asynchronous response
can be in the very distant future - from a temporal and eventual
perspective, so I must do a lot of housekeeping in my application and
remember which RPCs will lead to a response I must process and which I
have to ignore.
Imagine this example: a user clicks an action button 10 times and then
on the 'cancel' button 9 times. Due to network latencies or server
load, these RPCs can get out of the regular order - so which response
goes now with which request? Well, one could keep some running serial
numbers to pass from and forth - but that's just working around it, no?
> or even nicer, if the RPC invocation returned a handle which one
> then can cancel.
Well, I suppose if you created a cancelable AsyncCallback that your
application extended, then you would have your "handle"
something like
public abstract class CancelableCallback extends AsyncCallback {
private boolean canceled = false;
private List stack; // see text below
public CancelableCallback(List stack) {
stack.add(this);
this.stack = stack;
}
public void cancel() {
canceled = true;
this.stack.remove(this);
this.stack = null; // we're done with this
}
public void onSuccess(Object result) {
if (!canceled){
this.stack.remove(this);
this.stack = null; // we're done with this
onSuccessImpl(Object result);
}
}
public void onFailure(Throwable caught) {
if (!canceled){
this.stack.remove(this);
this.stack = null; // we're done with this
onFailureImpl(Throwable caught);
}
}
// for your subclasses to implement rather than the originals
public abstract void onSuccessImpl(Object result);
public abstract void onFailureImpl(Throwable caught);
}
> This is in general not easy at all, because the asynchronous response
> can be in the very distant future - from a temporal and eventual
> perspective, so I must do a lot of housekeeping in my application and
> remember which RPCs will lead to a response I must process and which I
> have to ignore.
not really ...
> Imagine this example: a user clicks an action button 10 times
your application adds each RPC's callback into a List when the rpc is
invoked ...
myService.invoke(some, params, new CancelableCallbackImpl(callStack));
> and then
> on the 'cancel' button 9 times.
The first element (callback) in the List is cancelled and removed
from the list each time the cancel button is pressed.
cancelButton.addClickListener(new ClickListener(){
public void onClick(Widget sender){
((CancelableCallback) callStack.get(0)).cancel();
}
}
I omitted some error checking and such for brevity, but you get the
idea.
> Due to network latencies or server load, these RPCs can get out of
> the regular order - so which response
> goes now with which request?
In this scenario, each request has its own callback (or handle), and
completed requests are removed from the call stack (List), so
the oldest outstanding RPC gets cancelled each time the cancel button
is pressed.
> Well, one could keep some running serial
> numbers to pass from and forth - but that's just working around it,
> no?
Aside from holding on to your call stack (java.util.List) there's not
much to keep track of here.
It is all pretty self maintaining and you don't have to worry about
serials and such.
-jason
> public abstract class CancelableCallback extends AsyncCallback {
>
> private boolean canceled = false;
> private List stack; // see text below
>
> public CancelableCallback(List stack) {
> stack.add(this);
> this.stack = stack;
> }
nice design.
i went down the same approach for other things that i have needed. in
fact i created a filter and built it into the framework because it
needed to be done repeatedly.
1.
http://javaongems.googlecode.com/svn/trunk/src/org/javaongems/client/rt/io/AsyncCallbackFilter.java
2.
http://javaongems.googlecode.com/svn/trunk/src/org/javaongems/client/AbstractGemlet.java
see snippet:
public AsyncCallbackFilter decorateCallback(AsyncCallback toDecorate,
Object[] args) {
HandleFailuresCallback failuresWrapper = new
HandleFailuresCallback(toDecorate);
FormLoadStatusCallback formWrapper = new FormLoadStatusCallback(null,
failuresWrapper);
if (args != null && args.length > 0 ) {
if (args[0] instanceof Form)
formWrapper.setForm((Form)args[0]);
}
return formWrapper;
}
above are the common decorations that i have needed to add. your
cancelation rpc response handling callback is good addition.
you can contribute it to the gems distributions if you care to.
rgds ash
http://www.gworks.com.au/
self help sources:
1. http://javaongems.org/ -> http://code.google.com/p/javaongems/
2. http://code.google.com/p/gems-gwt-user/
3. http://code.google.com/p/juls/