RFC : Provide access to Response objects in RPC callbacks

43 views
Skip to first unread message

BobV

unread,
Apr 8, 2008, 1:18:17 PM4/8/08
to Google Web Toolkit Contributors
Use cases:
- (Primary) Provide access to HTTP status codes for better
application-level handling of expected error conditions (403, 302)
- (Secondary) Use HTTP headers as a side-channel for communication

Non goals:
- Pluggable deserialization logic

Solution 1:
- Create a sub-type of InvocationException to provide HTTP-specific
information that will be pass to AsyncCallback.onFailure()
- Pros: Solves the primary use case, doesn't change existing
applications, and doesn't tie the core RPC interfaces to XHR-style
transport.
- Cons: Unclear how to handle the secondary use-case in the
onSuccess() situation.

Solution 2:
- Create a subtype of AsyncCallback or a mix-in interface for
AsyncCallback implementations that has a setResponse() method to be
called before onXYZ methods.
- Pros: Solves the primary and secondary use case in a consistent
manner; application-specific base callback classes can handle common
failure modes or side-channel responses.
- Cons: The callback object would have an implicit assumption on
XHR-style RPC implementations.


Solution 1 is simpler, but 2 brings the callback API up to parity with
the changes made to allow the RequestBuilder to be returned from the
async proxy objects.

--
Bob Vawter
Google Web Toolkit Team

Freeland Abbott

unread,
Apr 8, 2008, 1:36:51 PM4/8/08
to Google-Web-Tool...@googlegroups.com
Would a mix-in alongside AsyncCallback with a getResponse[Header]() API be viable?  It might be helpful to have the parsing be centralized...

Also, would such a mix-in be specifically a sibling to AsyncCallback  (i.e. AsyncCallbackExtension1, ...2, ...3), or have other mix-in applications?  (XHR/Responsewould be the obvious other peer, but those are classes not interfaces, and already have getters.)

Ian Petersen

unread,
Apr 8, 2008, 1:41:45 PM4/8/08
to Google-Web-Tool...@googlegroups.com
On Tue, Apr 8, 2008 at 1:18 PM, BobV <bo...@google.com> wrote:
>
> Use cases:
> - (Primary) Provide access to HTTP status codes for better
> application-level handling of expected error conditions (403, 302)
> - (Secondary) Use HTTP headers as a side-channel for communication

Your concerns that I've snipped include coming up with a design that
isn't tied to XHR. Are there any other transports besides XHR that
can provide access to HTTP status codes and headers? If not, then
what about punting on the issue? Something like, introduce a new
interface AsyncCallbackEx, for lack of a better name, that looks like
this:

public interface AsyncCallbackEx<T> {

void onFailure(Throwable caught, ToBeNamed responseInformation);

void onSuccess(T result, ToBeNamed responseInformation);
}

XHR-based transports can provide an instance of ToBeNamed that does
whatever seems useful/practical, and non-XHR-based transports either
can't transport RPC requests for services defined to work with
AsyncCallbackEx, or they pass null, or they pass an instance of
ToBeNamed that indicates no information is available. (Personally, I
think such transports should be defined to work in a way that the
ToBeNamed instance is up to the transport to figure out because the
transport might define a way to duplicate the status and headers into
the body of the response so that it can be parsed out and handed off
to the callback, although that might be defeated by your non-goal.)

Ian

--
Tired of pop-ups, security holes, and spyware?
Try Firefox: http://www.getfirefox.com

BobV

unread,
Apr 8, 2008, 2:02:43 PM4/8/08
to Google-Web-Tool...@googlegroups.com
On Tue, Apr 8, 2008 at 10:41 AM, Ian Petersen <ispe...@gmail.com> wrote:
>
> On Tue, Apr 8, 2008 at 1:18 PM, BobV <bo...@google.com> wrote:
> >
>
> > Use cases:
> > - (Primary) Provide access to HTTP status codes for better
> > application-level handling of expected error conditions (403, 302)
> > - (Secondary) Use HTTP headers as a side-channel for communication
>
> Your concerns that I've snipped include coming up with a design that
> isn't tied to XHR. Are there any other transports besides XHR that
> can provide access to HTTP status codes and headers?

The one that I'm thinking of is a pure cross-site implementation
based around injection of script tags that support search-style APIs
implemented in GWT as well as XHRs implemented from the Gears
worker-pool threads. It's kind of esoteric, but when you need to do
this, the current RPC API doesn't offer quite enough flexibility.

I'm leery of having a replacement type for AsyncCallback or getting
into a situation like IFace, IFace2, IFace3, etc. When you see that,
it's a sign that it's time to break out the weed-whacker and prune
something. The mix-in style would be something like

interface XHRAware {
void setResponse(http.client.Response);
}

and it allows for cleaner separation of concerns between the setters
and whatnot.

As far as parsing goes, the Respone object already has convenience
getters for status codes and headers. Only application-specific
parsing would be necessary.

Ian Petersen

unread,
Apr 8, 2008, 2:24:50 PM4/8/08
to Google-Web-Tool...@googlegroups.com
On Tue, Apr 8, 2008 at 2:02 PM, BobV <bo...@google.com> wrote:
> On Tue, Apr 8, 2008 at 10:41 AM, Ian Petersen <ispe...@gmail.com> wrote:
> > Your concerns that I've snipped include coming up with a design that
> > isn't tied to XHR. Are there any other transports besides XHR that
> > can provide access to HTTP status codes and headers?
>
> The one that I'm thinking of is a pure cross-site implementation
> based around injection of script tags that support search-style APIs
> implemented in GWT as well as XHRs implemented from the Gears
> worker-pool threads. It's kind of esoteric, but when you need to do
> this, the current RPC API doesn't offer quite enough flexibility.

Maybe this is due to ignorance on my part, but I don't feel like you
answered my question. Injecting script tags doesn't give you access
to HTTP status codes or headers, does it? As for XHRs from Gears, I
have no idea, but it's still XHR, by the looks of it, and so
"depending" on XHR in that case isn't really a problem.

> I'm leery of having a replacement type for AsyncCallback or getting
> into a situation like IFace, IFace2, IFace3, etc. When you see that,
> it's a sign that it's time to break out the weed-whacker and prune
> something.

True. Maybe GWT 1.5 should just break AsyncCallback if that's the
right way forward. There's a lot of work to do to upgrade from 1.4 to
1.5 anyway, so adding a parameter to your RPC invocations doesn't seem
like a big deal.

> The mix-in style would be something like
>
> interface XHRAware {
> void setResponse(http.client.Response);
> }
>
> and it allows for cleaner separation of concerns between the setters
> and whatnot.

But it also means you can't use anonymous callbacks, right? Every RPC
my app makes does this:

service.invokeRemote(args, new AsyncCallback<Foo>() {
// blah
});

Are you allowed to do this?

service.invokeRemote(args, new AsyncCallback<Foo> implements XHRAware() {
// blah
});

If not, then I find the whole mix-in approach distasteful. (Even if
the above code is valid, I still might find it distasteful based
solely on the much-increased line length.) (Although, I suppose GWT
could provide an XHRAwareAsyncCallback<T> in the standard library that
extends AsyncCallback<T> and XHRAware so that the mixing in happens
"in the background"--I suppose I'd be OK with that.)

I guess the main point of my previous post was that, as far as I know,
the only way to get access to HTTP status codes and headers is by
using XHR. Other transports just don't provide those features (again,
AFAIK). So, if my understanding is correct, then code that relies on
such status codes or headers is implicitly relying on XHR so you
could, presumably, just modify the RPC contract such that response
information is provided on a best-effort basis to all callbacks, or
such that certain RPC interfaces can specify that the side-band
information is necessary by using something other than AsyncCallback
in the Async service interface. If there's a transport besides XHR
that provides access to the side-band information then my whole point
is moot.

BobV

unread,
Apr 8, 2008, 6:22:45 PM4/8/08
to Google-Web-Tool...@googlegroups.com
On Tue, Apr 8, 2008 at 11:24 AM, Ian Petersen <ispe...@gmail.com> wrote:
> Maybe this is due to ignorance on my part, but I don't feel like you
> answered my question. Injecting script tags doesn't give you access
> to HTTP status codes or headers, does it? As for XHRs from Gears, I
> have no idea, but it's still XHR, by the looks of it, and so
> "depending" on XHR in that case isn't really a problem.

Script tag injection won't give you access to the headers; that's
why I pointed it out as a potential RPC transport mechanism and why
I'd like to avoid having the primary GWT RPC interfaces written
assuming that there's an XHR-style transport layer.

> > I'm leery of having a replacement type for AsyncCallback or getting
> > into a situation like IFace, IFace2, IFace3, etc. When you see that,
> > it's a sign that it's time to break out the weed-whacker and prune
> > something.
>
> True. Maybe GWT 1.5 should just break AsyncCallback if that's the
> right way forward. There's a lot of work to do to upgrade from 1.4 to
> 1.5 anyway, so adding a parameter to your RPC invocations doesn't seem
> like a big deal.

Modifying AsyncCallback in a way that's not source-compatible
wouldn't be my first choice because having access to the Response
object isn't something that's required for RPC to continue to work.

> > The mix-in style would be something like
> >
> > interface XHRAware {
> > void setResponse(http.client.Response);
> > }
> >
> > and it allows for cleaner separation of concerns between the setters
> > and whatnot.
>
> But it also means you can't use anonymous callbacks, right? Every RPC
> my app makes does this:
>
> service.invokeRemote(args, new AsyncCallback<Foo>() {
> // blah
> });
>
> Are you allowed to do this?
>
> service.invokeRemote(args, new AsyncCallback<Foo> implements XHRAware() {
> // blah
> });
>
> If not, then I find the whole mix-in approach distasteful. (Even if
> the above code is valid, I still might find it distasteful based
> solely on the much-increased line length.) (Although, I suppose GWT
> could provide an XHRAwareAsyncCallback<T> in the standard library that
> extends AsyncCallback<T> and XHRAware so that the mixing in happens
> "in the background"--I suppose I'd be OK with that.)

It doesn't make sense to have anything that is XHR-aware that isn't
also an AsyncCallback, so it'll probably look like
interface HTTPAsyncCallback extends AsyncCallback {....}

Miguel Méndez

unread,
Apr 8, 2008, 10:07:55 PM4/8/08
to Google-Web-Tool...@googlegroups.com


On Tue, Apr 8, 2008 at 1:18 PM, BobV <bo...@google.com> wrote:
Use cases:
 - (Primary) Provide access to HTTP status codes for better
application-level handling of expected error conditions (403, 302)
 - (Secondary) Use HTTP headers as a side-channel for communication
Non goals:
 - Pluggable deserialization logic
Solution 1:
 - Create a sub-type of InvocationException to provide HTTP-specific
information that will be pass to AsyncCallback.onFailure()
 - Pros: Solves the primary use case, doesn't change existing
applications, and doesn't tie the core RPC interfaces to XHR-style
transport.
 - Cons: Unclear how to handle the secondary use-case in the
onSuccess() situation.
 
We should have always synthesized an exception for failed HTTP status codes.  We could create a subtype of InvocationException or a new exception type to handle these HTTP failures.  Either way, the failure capture information for the specific exception type should include the Response instance.  That would handle the bulk of the problem.  We should do this whether or not we go after the secondary use case of side-channel communications.  I must admit that I'm not clear about what that scenarios actually necessitate header based side channels.  Is Spring one case of this?
 
Solution 2:
 - Create a subtype of AsyncCallback or a mix-in interface for
AsyncCallback implementations that has a setResponse() method to be
called before onXYZ methods.
 - Pros: Solves the primary and secondary use case in a consistent
manner; application-specific base callback classes can handle common
failure modes or side-channel responses.
 - Cons: The callback object would have an implicit assumption on
XHR-style RPC implementations.
 
FWIW, AsyncCallback is parameterized so you could make the argument a parameterization itself.  Then you would not have to introduce a new callback interface or create a protocol for setting the response object.  Pick a name that you like but you could do the following:
 
/**
 * @param <T> Expected return type used in the synchronous method signature
 */
class ResultWithHttpResponse<T> {
  ResultWithHttpResponse(T sycnMethodReturnType) { ... }
  Response getHTTPResponse() { ... }
  T getResult();
It would be good to detail some concrete scenarios where access to the HTTP headers during the AsyncCallback.onSuccess method is necessary before really tackling this.
Solution 1 is simpler, but 2 brings the callback API up to parity with
the changes made to allow the RequestBuilder to be returned from the
async proxy objects.
 
Solution 1 is simpler and I think that we should address it whether or not we decide to augment the asynccallback to expose the HTTP Response object.
 
--
Bob Vawter
Google Web Toolkit Team



--
Miguel

Bruce Johnson

unread,
Apr 9, 2008, 8:54:40 AM4/9/08
to Google-Web-Tool...@googlegroups.com
I agree with Miguel completely on this one: Subclass InvocationException such that you can access the Response.

Let's call the other variants "post-1.5" considerations.
--
Join us at Google's biggest developer event of the year
May 28-29, San Francisco
http://code.google.com/events/io

ssozonoff

unread,
May 2, 2008, 5:37:46 AM5/2/08
to Google Web Toolkit Contributors
Hello all,

Just to chime in a little with the current issue I am facing ... my
use case ...

-- context --
Today we have a server side component written in Spring and protected
with Acegi and integrated with our CAS (single sign-on solution)
server.
We have applied security at the method level in the Java Service
Layer.
-- end context --

Today we are writting a little console in GWT which sits on top of
this java service layer.

The way this stuff (Acegi) works in a fairly "out of the box" manner
is that our GWT server side code consumes methods from the java pojo
facade (service layer)
If a service layer method is called without the user having been
authenticated (I am only talking about authentication here, not
permissions) an AuthenticationException is thrown by Acegi.

This exception bubbles up the stack and is intercepted by a servlet
filter (Acegi) which catches this exception and converts it into a 302
redirect with the login URL of the CAS server.

In GWT 1.4 there is no way to handle this in AsynCallback.onFailure().
With a snapshot from SVN HEAD it is now possible to get the server
response code, but this does not give me access to the actual redirect
URL.... for this I would need access to the response object.

Now I am not sure that the above is the most elegant way to address
this problem and I have tried other alternatives like catching the
Acegi AuthenticationException and converting it to a class extending
SerializableException which I rethrow at the GWT client and catch in
onFailure().
This works of course but also has its own set of cons.... so I am, as
yet, still undecided on the final route to take.

But in any case I just wanted to present a use case which supports the
requirement to

a. Capture the server response code (this is done in 1.5)
b. acess the response content so I can get the redirect URL

Thanks,
Serge

Reply all
Reply to author
Forward
0 new messages