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
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
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.
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.
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 {....}
Use cases:- (Primary) Provide access to HTTP status codes for betterapplication-level handling of expected error conditions (403, 302)- (Secondary) Use HTTP headers as a side-channel for communicationNon goals:- Pluggable deserialization logicSolution 1:- Create a sub-type of InvocationException to provide HTTP-specificinformation that will be pass to AsyncCallback.onFailure()- Pros: Solves the primary use case, doesn't change existingapplications, and doesn't tie the core RPC interfaces to XHR-styletransport.- Cons: Unclear how to handle the secondary use-case in theonSuccess() situation.
Solution 2:- Create a subtype of AsyncCallback or a mix-in interface forAsyncCallback implementations that has a setResponse() method to becalled before onXYZ methods.- Pros: Solves the primary and secondary use case in a consistentmanner; application-specific base callback classes can handle commonfailure modes or side-channel responses.- Cons: The callback object would have an implicit assumption onXHR-style RPC implementations.
/*** @param <T> Expected return type used in the synchronous method signature*/class ResultWithHttpResponse<T> {ResultWithHttpResponse(T sycnMethodReturnType) { ... }Response getHTTPResponse() { ... }T getResult();}
Solution 1 is simpler, but 2 brings the callback API up to parity withthe changes made to allow the RequestBuilder to be returned from theasync proxy objects.
--Bob VawterGoogle Web Toolkit Team