Give access to "request" and "response" objects when making an RPC call

1,118 views
Skip to first unread message

Marwan Singer

unread,
Nov 9, 2007, 1:22:02 PM11/9/07
to Google Web Toolkit Contributors
I have a little architectural problem that can't be solved with
current release of GWT.

Server-side, my implementation manages and stores, for each client,
some kind of "conversation state" information. That "conversation
state" information transits back and forth between the server and the
client within the HTTP response & HTTP Request headers.

Using a com.google.gwt.http.client.RequestBuilder , I can easily
access those headers. They are available to the client.

Now, for an RPC call (com.google.gwt.user.client.rpc.RemoteService) ,
I can't get access to those headers. Google made it so, that all the
low-level details are hidden and unavailable to the client.

I could of course adapt the code myself to get the feature, but think
would be a good idea to include it within standard GWT.

Let me know what you think!

Regards,

Marwan SINGER

Ray Cromwell

unread,
Nov 9, 2007, 1:32:01 PM11/9/07
to Google-Web-Tool...@googlegroups.com
This feature already exists, see getThreadLocalRequest()
(http://google-web-toolkit.googlecode.com/svn/javadoc/1.4/com/google/gwt/user/server/rpc/RemoteServiceServlet.html#getThreadLocalRequest())

When in doubt, you should check the docs, FAQ, Gwt-Web-Toolkit
(non-contributors) group, and Issue Tracker before suggesting features
to the contributors list.

-Ray

Ian Petersen

unread,
Nov 9, 2007, 1:35:37 PM11/9/07
to Google-Web-Tool...@googlegroups.com
On 11/9/07, Ray Cromwell <cromw...@gmail.com> wrote:
> This feature already exists, see getThreadLocalRequest()

I think he's talking client-side, though. getThreadLocalRequest()
only works server-side.

Ian

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

Miguel Méndez

unread,
Nov 9, 2007, 1:36:12 PM11/9/07
to Google-Web-Tool...@googlegroups.com
We have a patch that is going into GWT 1.5 which will allow you to access the underlying com.google.gwt.http.client.Request object.  See issue 535 for more details.  However, the Request object that you get does not allow you to set headers and the Response object is not exposed outside of RPC.

What is the nature of the conversation state that prevents you from including it in the payload proper?
--
Miguel

Ray Cromwell

unread,
Nov 9, 2007, 2:30:39 PM11/9/07
to Google-Web-Tool...@googlegroups.com
Oh, my apologies. I didn't read it closely enough. I can see a use for
this, especially if you have to set authorization headers in an RPC
call, for example, if you have your entire web app sitting behind a
servlet filter which enforces container level
authentication/authorization.

-Ray

Peter Blazejewicz

unread,
Nov 9, 2007, 3:51:35 PM11/9/07
to Google Web Toolkit Contributors
hi Marwan,

considering exposing RPC underlying impelentation usefull (there are
jire enhancement request for that, +1) currently there is design
solution for client/server communication to pass discretional/state
information between requests:
- wrap your DTO object into another object
- DTO should have dedicated field to store discretional information
about state
I've seen pattern being proposed many times on regular group when
discussing how to pass some value between GWT RPC based requests

{"mySharedToken":"GENERATED_TOKEN", "success": true, "MyBeans":
{"MyBean":[......]}, "resultsLength":20.0, "currentPage":5.0}

(sorry for JSON format but it should be easier to see it in quick
shot),

regards,
Peter

Ray Cromwell

unread,
Nov 9, 2007, 5:12:09 PM11/9/07
to Google-Web-Tool...@googlegroups.com
One example, although it's probably not recommended, if you're using a
federated authentication/authorization system like Google ClientLogin
or OAuth, you're required to set the Authorization header in the HTTP
request, so if there was an OAuth protected RPC service, you might
need to do this. I once hacked up a GWT Google ClientLogin before
AuthSub was available, to do just that, perform the ClientLogin
protocol in the browser (one time token only, no session token)

-Ray

Rob Jellinghaus

unread,
Nov 12, 2007, 12:40:43 PM11/12/07
to Google Web Toolkit Contributors
On Nov 9, 10:36 am, "Miguel Méndez" <mmen...@google.com> wrote:
> However, the Request object that you get does not allow
> you to set headers and the Response object is not exposed outside of RPC.
>
> What is the nature of the conversation state that prevents you from
> including it in the payload proper?

I'm familiar with what he's talking about from my work with Seam,
which provides conversation support as one of its primary use cases.
The key thing about Seam conversation support is that it is
*declarative*. You can specify methods as being conversational, and
when you invoke those methods, it creates a conversational state
context on the server which affects the runtime state of the
components that service those methods (and subsequent ones invoked on
those components).

Essentially, modern server-side component frameworks such as Seam give
you techniques to define scopes that control the state of those
components, *without* modifying the interfaces of the components
themselves. The state scoping is declared through annotations and
could be considered an "aspect" of the components. Exposing the
conversational state in the interface (e.g. in the payload) breaks
this declarativeness and obfuscates the interface. The necessary
conversational state is logically an out-of-band token in the request/
response flow, exactly like the HTTP session cookie is.

A shorter version of this explanation: the conversation state
shouldn't be in the payload proper for exactly the same reason that
the HTTP session cookie shouldn't be in the payload proper; both of
them are metadata about the server interaction, not actual payload or
interface content.

+1 on the suggestion to make the Request object exposed by issue 535
allow access to (and mutation of) HTTP headers; I would want to use
this in a Seam/GWT integration.

Cheers!
Rob

Miguel Méndez

unread,
Nov 12, 2007, 1:20:36 PM11/12/07
to Google-Web-Tool...@googlegroups.com
By the time that you get the Request object back as part of the patch for issue 535, the request has already been sent.  All you can do is cancel the HTTP request.

I think that this should be a new enhancement request.  It would be good to include some sample code that demonstrates how this conversation state could be exposed to a caller.

On Nov 12, 2007 12:40 PM, Rob Jellinghaus <rjelli...@gmail.com> wrote:

On Nov 9, 10:36 am, "Miguel Méndez" <mmen...@google.com> wrote:
> However, the Request object that you get does not allow
> you to set headers and the Response object is not exposed outside of RPC.
>
> What is the nature of the conversation state that prevents you from
> including it in the payload proper?

I'm familiar with what he's talking about from my work with Seam,
which provides conversation support as one of its primary use cases.
The key thing about Seam conversation support is that it is
*declarative*.  You can specify methods as being conversational, and
when you invoke those methods, it creates a conversational state
context on the server which affects the runtime state of the
components that service those methods (and subsequent ones invoked on
those components).

Essentially, modern server-side component frameworks such as Seam give
you techniques to define scopes that control the state of those
components, *without* modifying the interfaces of the components
themselves.  The state scoping is declared through annotations and
could be considered an "aspect" of the components.  Exposing the
conversational state in the interface ( e.g. in the payload) breaks

Marwan Singer

unread,
Nov 12, 2007, 6:32:16 PM11/12/07
to Google Web Toolkit Contributors
I am fully in-line with Rob. I am using "Spring webflow", which does
the same thing as what "Seam" does: Based on configuration, It creates
a "flow context" instance on the server. The client needs to read it,
and send it back to the server with each subsequent request. The
server is then able to give a context to the incoming request and
provide adequate services and possible transitions to a new state of
the conversation.

Since this data is pure meta-data, I would like to be able to keep it
out of the business services interfaces.

As for the code/interface samples, I have a couple of ideas that I
could maybe propose, if you'd like, when they are a bit more
structured.

Regards,

Marwan SINGER

Rob Jellinghaus

unread,
Nov 12, 2007, 6:54:45 PM11/12/07
to Google Web Toolkit Contributors
Marwan, why don't you and I take this offline until we have a more
concrete proposal to put into a Jira enhancement request?

Cheers!
Rob
http://robjsoftware.org

rsheldon

unread,
Nov 14, 2007, 1:02:33 AM11/14/07
to Google Web Toolkit Contributors
Just to add my $0.02...

I'm all in favor of being able to access/mutate the rpc request
headers. I think this is very important for (eg) security tokens. I am
fundamentally opposed to extending the business interface just to
allow security tokens (or other state) to be passed in.

How about having a listener interface for an RPC call that allows the
client code to access/modify the request before it gets sent to the
server. Perhaps AsynCallback could be extended to support a new method
for this type of interaction, or in the interest of backwards
compatibility, a new interface which extends from AsynCallback?

For example, in order to set a security token of some kind (this is
pseudo-ish code)

ExtendedAsynCallback callback = new ExtendedAsynCallback() {

public void onRequest(Request request) {
request.setHeader("my-security-header", someValue);
}

public void onResponse(Request request, Response response) {
someOtherValue = response.getHeader("someHeaderName");
}

public void onFailure(Throwable t) {
...
}

public void onSuccess(Object o) {
...
}


Or something along those lines.
Cheers,
Richard

Miroslav Pokorny

unread,
Nov 14, 2007, 2:23:27 AM11/14/07
to Google-Web-Tool...@googlegroups.com
First problem adding headers to a request.

Why not make all rpc proxies implement an interface (lets call it RpcProxy) and have that interface define a few methods that help one work with headers eg
addHeader( String name, String value )

The problem with this approach is that proxies are now not stateless.

Second problem getting headers within a response...
Perhaps add an interface that extends AsyncCallback that adds a few methods to get headers from the response.

Bruce Johnson

unread,
Nov 16, 2007, 10:34:36 PM11/16/07
to Google-Web-Tool...@googlegroups.com
Something like mP's idea makes sense to me. Proxies already have state (i.e. ServiceDefTarget), so adding another interface you can optionally cast to, such as ServiceConfig, seems appropriate.

But, yes, this is a separate feature request. A pretty useful one!

Miguel Méndez

unread,
Nov 19, 2007, 12:21:06 PM11/19/07
to Google-Web-Tool...@googlegroups.com
On Nov 16, 2007 10:34 PM, Bruce Johnson <br...@google.com> wrote:
Something like mP's idea makes sense to me. Proxies already have state (i.e. ServiceDefTarget), so adding another interface you can optionally cast to, such as ServiceConfig, seems appropriate.

But, yes, this is a separate feature request. A pretty useful one!


On Nov 14, 2007 6:23 PM, Miroslav Pokorny <miroslav...@gmail.com> wrote:
First problem adding headers to a request.

Why not make all rpc proxies implement an interface (lets call it RpcProxy) and have that interface define a few methods that help one work with headers eg
addHeader( String name, String value )

The problem with this approach is that proxies are now not stateless.

Is it sufficient to specify headers that affect all methods on a particular proxy?  Or do people have use cases that would require method specific headers?
 

Second problem getting headers within a response...
Perhaps add an interface that extends AsyncCallback that adds a few methods to get headers from the response.


We would need to expose a new interface that allows the callback to access the response headers.  This is one scenario where it would have been nice to have an event object style callback.




--
Miguel

Miroslav Pokorny

unread,
Nov 19, 2007, 2:50:38 PM11/19/07
to Google-Web-Tool...@googlegroups.com
On Nov 20, 2007 4:21 AM, Miguel Méndez <mme...@google.com> wrote:
On Nov 16, 2007 10:34 PM, Bruce Johnson <br...@google.com> wrote:
Something like mP's idea makes sense to me. Proxies already have state (i.e. ServiceDefTarget), so adding another interface you can optionally cast to, such as ServiceConfig, seems appropriate.

But, yes, this is a separate feature request. A pretty useful one!


On Nov 14, 2007 6:23 PM, Miroslav Pokorny <miroslav...@gmail.com> wrote:
First problem adding headers to a request.

Why not make all rpc proxies implement an interface (lets call it RpcProxy) and have that interface define a few methods that help one work with headers eg
addHeader( String name, String value )

The problem with this approach is that proxies are now not stateless.

Is it sufficient to specify headers that affect all methods on a particular proxy?  Or do people have use cases that would require method specific headers?

Well  considering that JS is singlethreaded this is not really a problem. Its not a nice elegant solution.

A better option that doesnt break the statelessness of the proxy might be to introduce a new interface or even concrete class.

class/interface Headers
void addHeader( name,value)
void setHeader( name, value).
Iterator iterator()
String[] getHeader( name );

If the 2nd last parameter of the method is a Header something special happens.

last parameter - AsyncCallback
if 2nd last parameter is a Header - The headers inside the Header are read and added to the request. In this case 0 to last -2 are actual method parameters.
else 0 to last - 1 are actual method parameters.


 

Second problem getting headers within a response...
Perhaps add an interface that extends AsyncCallback that adds a few methods to get headers from the response.


We would need to expose a new interface that allows the callback to access the response headers.  This is one scenario where it would have been nice to have an event object style callback.

My idea was to create a new interface that called XYZ. This new interface would have methods to set / add the return status code / headers etc. If the callback parameter passed to the method implemented XYZ then the proxy would do the cast and record the headers.

Or one could create a new interface that extends AsyncCallback which contains extra methods to set/add the return status code / headers and so on.
 



--
mP

Marwan Singer

unread,
Nov 21, 2007, 8:13:51 AM11/21/07
to Google Web Toolkit Contributors
I have followed this thread quite closely the last days. I also looked
at the GWT code to understand what the possibilities could be. I'll
share my thoughts with you. Please review and adjust my comments.

From a GWT user perspective, I would like:

1- Consistency accross RPC Requests & standard Requests handling:
Thus, being able to work the same way with both RPC services Requests
and standard Requests (obtained from
com.google.gwt.http.client.RequestBuilder);
2- Reusability of Request Handlers: If I define a request handler to
read and interpret security headers, I'd like to make it generic so
that it can be used transparently with all my RPC services requests
and standard Requests (obtained from
com.google.gwt.http.client.RequestBuilder);
3- Modularity: Would like to be able to define specialized request
handlers (i.e. one for conversation handling, one for security
handling, one for view management handling, ...);

==> Because RPC Requests & standard Requests both end up, at some
point, as com.google.gwt.http.client.Request object, I was thinking
about using this last object for full-filling requirement1;
==> Define a new interface, implementations of which, is left to the
GWT user. Concrete classes may be used and re-used with RPC services
requests and standard Requests;
==> Each implementation of the interface is specialized in a specific
area; GWT allows for several implementations to be called for a single
call;


STEP1: The new interface:
--------------------------------------
public interface com.google.gwt.http.client.RequestInterceptor
{
/**
* Lifecycle method called right before a request is fired to the
server.
* The request object offers some handy operations to the client,
like addHeader(String headerKey, String headerValue),
addHeaders(Map<String, String> headers), ...;
* Interceptors are called in a chain, and each handler in the
chain may break the chain by returning false. Returning false not only
breaks the chain,
* but also prevents the request to be sent.
*
* @param com.google.gwt.http.client.Request Wrapper around the
request object.
* @return false if next handler in the chain should not be
called.
*/
public boolean doHandleBefore(com.google.gwt.http.client.Request
request);

/**
* Lifecycle method called right after a response is received from
the server (in an aysnchronous way).
* The response object offers some handy operations, like String
getHeader(String headerKey), Header[] getHeaders(), ...;
*
* @param com.google.gwt.http.client.Request Wrapper around the
request object.
* @param com.google.gwt.http.client.Response Wrapper around the
returned response object.
*/
public void doHandleAfter(com.google.gwt.http.client.Request
request, com.google.gwt.http.client.Response response);
}
STEP2: The interface implementations:
---------------------------------------------------------
/**
* implementation of a ConversationHandler.
*/
public class be.md3.MyConversationRequestHandler implements
RequestInterceptor{
public boolean doHandleBefore(Request request) throws
Exception{
// Do my stuff to hanlde conversation specific pre-processing
...
request.addHeader("conversation-context", context.toString());
...
if(success) return true /* Call next one in the chain */;
else return false /* Break the chain */;
}

public void handleAfter(Response response) throws Exception{
// Do my stuff to hanlde conversation specific post-
processing
String ctx = response.getHeader("conversation-context");
}
}
/**
* implementation of another RemoteRequestHandler.
*/
public class be.md3.MyOtherRequestHandler implements
RequestInterceptor{
public boolean doHandleBefore(Request request) throws Exception{
// Do my stuff to hanlde something else specific pre-
processing
return true /* Always call next one in the chain */;
}

public void doHandleAfter(Response response) throws Exception{
// Do my stuff to hanlde something else specific post-
processing
}
}
STEP3: Passing my interfaces to the request
------------------------------------------------------------------
com.google.gwt.http.client.Request class defines a new instance
variable:

public class Request {
...
/*
* request interceptors: to be set via constructor or via
Setters
*/
private RequestInterceptor[] requestInterceptors;
...
}

The RPC services as well as the
com.google.gwt.http.client.RequestBuilder both allow for an array of
interceptors to be set (either via adequate constructors and/or
setters);

STEP4: execution of the interceptors
------------------------------------------------------
GWT code guarantees that interceptors are executed at the right time,
from what I could analyze, probably within XMLHTTPRequest :

public class com.google.gwt.http.client.XMLHTTPRequest{
static native String send(JavaScriptObject xmlHttpRequest,
Request httpRequest, String requestData, RequestCallback callback){
// Call Request.doHandleBefore(Request httpRequest) before the
call is performed;

// Call Request.doHandleAfter(Request httpRequest,
com.google.gwt.http.client.Response response) after the response is
generated;
}
}

GWT code guarantees that interceptors are called in the sequence of
the array;
GWT code guarantees that if an interceptor returns false, then the
next interceptor is not executed and the request not launched;

Marwan SINGER

On Nov 19, 8:50 pm, "Miroslav Pokorny" <miroslav.poko...@gmail.com>
wrote:
> On Nov 20, 2007 4:21 AM, Miguel Méndez <mmen...@google.com> wrote:
>
>
>
> > On Nov 16, 2007 10:34 PM, Bruce Johnson <br...@google.com> wrote:
>
> > > Something like mP's idea makes sense to me. Proxies already have state (
> > > i.e. ServiceDefTarget), so adding another interface you can optionally
> > > cast to, such as ServiceConfig, seems appropriate.
>
> > > But, yes, this is a separate feature request. A pretty useful one!
>
> > > On Nov 14, 2007 6:23 PM, Miroslav Pokorny <miroslav.poko...@gmail.com>

Miguel Méndez

unread,
Nov 21, 2007, 11:08:23 AM11/21/07
to Google-Web-Tool...@googlegroups.com, Rob Jellinghaus
On Nov 19, 2007 2:50 PM, Miroslav Pokorny <miroslav...@gmail.com> wrote:

On Nov 20, 2007 4:21 AM, Miguel Méndez <mme...@google.com> wrote:
Is it sufficient to specify headers that affect all methods on a particular proxy?  Or do people have use cases that would require method specific headers?

Well  considering that JS is singlethreaded this is not really a problem. Its not a nice elegant solution.

Yes, I agree that calling and then resetting the state would not be very user friendly.  I was hoping to get more insight into how people would envision using this capability.


A better option that doesnt break the statelessness of the proxy might be to introduce a new interface or even concrete class.

class/interface Headers
void addHeader( name,value)
void setHeader( name, value).
Iterator iterator()
String[] getHeader( name );

You want to be able to specify the same information that you can with RequestBuilder.  This would be headers, password, timeout, and user.  So, the type that you would pass to the async method would probably look like this:

public abstract class RequestMetadata {
  public abstract Header[] getHeaders();
  public abstract String getPassword();
  public abstract int getTimeoutMillis();
  public abstract String getUser();
}

We could also provide a builder for the RequestMetadata which could be factored out of RequestBuilder.


If the 2nd last parameter of the method is a Header something special happens.

last parameter - AsyncCallback
if 2nd last parameter is a Header - The headers inside the Header are read and added to the request. In this case 0 to last -2 are actual method parameters.
else 0 to last - 1 are actual method parameters.

That would be a simple way to specify it.  Given that approach the following code would look like:
// Synchronous service definiton
interface MyService extends RemoteService {
  List<MyItems> getItems();
}

// Asynchronous service definition
interface MyServiceAsync {
  Request getItems(RequestMetadata requestMetadata, AsyncCallback<ResponseMetadata<List<MyItems>>> callback);
}
 


Second problem getting headers within a response...
Perhaps add an interface that extends AsyncCallback that adds a few methods to get headers from the response.


We would need to expose a new interface that allows the callback to access the response headers.  This is one scenario where it would have been nice to have an event object style callback.

My idea was to create a new interface that called XYZ. This new interface would have methods to set / add the return status code / headers etc. If the callback parameter passed to the method implemented XYZ then the proxy would do the cast and record the headers.

Or one could create a new interface that extends AsyncCallback which contains extra methods to set/add the return status code / headers and so on.
 

Now that some time has passed, do we need a subtype of AsyncCallback?  We could simply declare a generic type that would be used in place of T in the AsyncCallback.  Something like:

public abstract class ResponseMetadata<T> {
  public abstract Request getRequest();
  public abstract Response getResponse();
  public abstract T getResult();
}

--
Miguel

Miguel Méndez

unread,
Nov 21, 2007, 11:11:44 AM11/21/07
to Google-Web-Tool...@googlegroups.com
This seems a little complex.  What advantage does this interceptor approach afford over simply using a type that specifies all of the necessary information up front and avoids the chaining?

       request.addHeader ("conversation-context", context.toString());

Ian Petersen

unread,
Nov 21, 2007, 1:18:32 PM11/21/07
to Google-Web-Tool...@googlegroups.com
On Nov 21, 2007 11:08 AM, Miguel Méndez <mme...@google.com> wrote:
> // Asynchronous service definition
> interface MyServiceAsync {
> Request getItems(RequestMetadata requestMetadata,
> AsyncCallback<ResponseMetadata<List<MyItems>>> callback);
> }

What is the meaning of AsyncCallback<ResponseMetadata<List<MyItems>>>?
My understanding was that a Java 1.5-enabled GWT would parameterize
the AsyncCallback by the expected return type so that onSuccess()
could receive an object of that type, rather than of type Object. Is
it a nod to backwards compatibility to throw a ResponseMetadata into
the type parameterization? If so, it seems easier to me as a user of
the API to modify the RPC generators to acknowledge two types of
client-side interface that accept either the old style (with no
response metadata) or a new style where AsyncCallback is something
like this:

public interface AsyncCallback2<T> {

void onFailure(Throwable t); // as before

void onSuccess(T result, ResponseMetadata meta);
}

Perhaps AsyncCallback2 is a terrible name, but my point is that a
hairy type parameterization seems painful and I'd rather solve the
backwards compatibility issue a different way (assuming that the hairy
type parameterization has anything to do with compatibility).

Miguel Méndez

unread,
Nov 21, 2007, 1:53:26 PM11/21/07
to Google-Web-Tool...@googlegroups.com
This was just brainstorming about how we could extend the asynchronous method signatures to allow a developer to provide additional information for the request and also get additional information about the response.  I was not explicit in my reply, but the idea that I threw out there would be an optional form that you could use if you wanted to access this metadata.  So, it is not about backwards compatibility.  If you don't care to, you can still use the form that you would expect.

interface MyServiceAsync {
  void getItems(AsyncCallback<List<MyItems>> callback);
}

If you wanted to configure the HTTP request information and you wanted to inspect the HTTP response, the you could use this form:
interface MyServiceAsync {
  void getItems(RequestMetadata requestMetadata, AsyncCallback<ResponseMetadata<List<MyItems>>> callback);
}

We could introduce a new callback type for the metadata case if we wanted to, but it did not seem strickly necessary.
--
Miguel

Ian Petersen

unread,
Nov 21, 2007, 2:05:47 PM11/21/07
to Google-Web-Tool...@googlegroups.com
So I assume the "expected" interface would work as expected: same as
GWT 1.4, but a typesafe onSuccess(). How do you imagine the
ResponseMetadata-enhanced version working? Would it be something like
this?

proxy.invokeService(arguments, new
AsyncCallback<ResponseMetadata<List<MyItems>>>() {

public void onFailure(Throwable t) {
// whatever
}

public void onSuccess(ResponseMetadata<List<MyItems>> result) {
// retrieve headers, etc. directly from result

// obviously we'd need a good name here, rather than some
spur-of-the-moment thing
List<MyItems> realResult = result.getRealResult();
}
});

What would you do with server-side actions that result in onFailure()
being called? Is there a way to let the onFailure method inspect
response headers and so on? Would it make any sense for an RPC method
to do things like return a 403 Not Authorized by throwing an
exception? Does anyone care about headers in the failure case? If
people care about headers in the failure case, what do you do about
failures that are so early as not to have a response object?

Miguel Méndez

unread,
Nov 21, 2007, 4:30:54 PM11/21/07
to Google-Web-Tool...@googlegroups.com
On Nov 21, 2007 2:05 PM, Ian Petersen <ispe...@gmail.com> wrote:

So I assume the "expected" interface would work as expected: same as
GWT 1.4, but a typesafe onSuccess().  

Yes.  Both of the following snippets would work in GWT 1.5

// GWT 1.4 style still works
interface MyServiceAsync {
  void getItems(AsyncCallback callback);
}

// GWT 1.5 style, still works

interface MyServiceAsync {
  void getItems(AsyncCallback<List<MyItems>> callback);
}
How do you imagine the
ResponseMetadata-enhanced version working?  Would it be something like
this?

proxy.invokeService(arguments, new
AsyncCallback<ResponseMetadata<List<MyItems>>>() {

 public void onFailure(Throwable t) {
   // whatever
 }

 public void onSuccess(ResponseMetadata<List<MyItems>> result) {
   // retrieve headers, etc. directly from result

   // obviously we'd need a good name here, rather than some
spur-of-the-moment thing
   List<MyItems> realResult = result.getRealResult();
 }
});

Basically.  ResponseMetadata would also have an accessor that returns the HTTP module's Response instance.  (We may want to also provide an accessor for the Request instance).


What would you do with server-side actions that result in onFailure()
being called?  

We should do what we do today and call onError method with an exception that describes the failure.
 
Is there a way to let the onFailure method inspect
response headers and so on? 
Would it make any sense for an RPC method
to do things like return a 403 Not Authorized by throwing an
exception?  Does anyone care about headers in the failure case?  If
people care about headers in the failure case, what do you do about
failures that are so early as not to have a response object?

Very good points.  In the general case, the onFailure method cannot inspect the headers for the very reason that you point out.  The ability to inspect the headers should be based on the specific exception type passed to the onError method.

For example, now that we are using RequestBuilder for RPC, we could check for HTTP failure status codes.  In the case of an HTTP failure status code, we could pass an HTTPException (or whatever) to the onError method that includes the Request and Response instances as part of the failure capture information.  I had talked internally about enabling this but it did not get much tracking so I left it out.  However, we could add this capability.

--
Miguel
Reply all
Reply to author
Forward
0 new messages