Wednesday, March 30, 2011

Re: Making RPC access logs intelligible

Philippe, Kelsey - thanks for the very helpful responses. This sort
of additional proxy behavior feels like something that would be of
considerable value as a standard part of GWT. I'm surprised there
aren't considerably more complaints in this group.

setServiceEntryPoint() was the magic button I was looking for.
However, I ended up coming up with an alternative that fits my
(heavily Guice-dependent) architecture a little better. Since your
responses were so good (I wish I could give you stackoverflow points),
I feel obligated explain what I did.

This involves a larger number of artifacts than I would prefer, but it
feels fairly natural to me:

* I derived a new GuiceRemoteServiceServlet that overrides
processCall() to look up the interface in the Guice injector and
execute code on throwaway objects.
* I created separate interface, interfaceAsync, and implementation
classes for every single method. Each interface has a different
@RemoteServiceRelativePath. Some of the impl classes handle multiple
interfaces when there is appropriate shared logic.
* I map the interfaces to implementation in GuiceConfig.
* I created a Gin singleton that implements all the async interfaces
and proxies to the individual gwt-rpc proxies; this keeps my client
code blissfully ignorant of the complexity.

It's a little painful to add an RPC method:

* Create new interface and interfaceAsync
* Implement the interface with a new impl class or on an existing impl class
* Map the interface to impl in Guice
* Add the async interface to the Gin singleton proxy

On the other hand my biz logic is now the way I want it to be -
wrapped up in small, modular, reusable, appropriately scoped,
guice-injected chunks. Parameter/method changes refactor nicely with
Eclipse. I could eliminate the mapping step with annotations if I was
willing to accept the startup time penalty of classpath scanning, and
I could probably even generate the Gin singleton if I wanted. But my
remote interface doesn't change that often.

This may not be for everyone, but for a DI addict like me it seems
pretty reasonable. And my appengine logs are now beautiful again -
current load, errors, and individual log entries are now broken down
by method call.


On Wed, Mar 30, 2011 at 4:33 AM, Kelsey Francis <> wrote:
> Jeff,
> You could create a common subclass (let's call it JeffRemoteServiceServlet)
> of RemoteServiceServlet that overrides the
> onAfterRequestDeserialized(RPCRequest) method. That method is called, as the
> name implies, everytime the servlet receives an RPC request, so it's the
> perfect spot to collect information for logging.
> That doesn't get you the timing information you're after, though, so you
> could instead override RemoteServiceServlet.processCall(String) to
> 1. Start a timer (i.e., record System.nanoTime() or whatever)
> 2. Call super.processCall
> 3. Stop the timer
> Now, so long as all of your service implementations override
> JeffRemoteServiceServlet, you've got the desired behavior everywhere. I'm
> not sure where the best spot to do the actual averaging would be, but this
> should at least let you hook in at the right spot.
> Another (much more difficult) option, that you and Philippe have alluded to,
> is to call setServiceEntryPoint client-side and pipe all of your RPC
> requests through a single servlet. You can make this happen automatically,
> or even completely take over the RPC transport process by creating a custom
> proxy generator. We've done this, and as you mentioned, it's a little
> difficult to wrap your head around at first, but once you have, the changes
> are actually pretty minor (unless you decide to start adding features like
> batching, etc.). You'd need:
> 1. A new subclass of RemoteServiceProxy (let's call it
> DispatchedRemoteServiceProxy) that overrides doInvoke() to take control of
> the transport of the request
> 2. A new subclass of ProxyCreator (let's call it
> DispatchedRemoteProxyCreator) that overrides getProxySupertype() to
> return DispatchedRemoteServiceProxy.class
> 3. A new subclass of ServiceInterfaceProxyGenerator (let's call it
> DispatchedRemoteServiceGenerator) that overrides createProxyCreator() to
> return a new DispatchedRemoteProxyCreator
> 4. Have your services inherit a new interface (DispatchedRemoteService) and
> set up your .gwt.xml file generate impls of that interface with
> DispatchedRemoteServiceGenerator.
> The trickiest part is what to do in DispatchedRemoteServiceProxy.doInvoke().
> You'll want to make a request to your special dispatch servlet, of course,
> and then decode it once you get a response. RequestCallbackAdapter holds the
> keys to making this happen. Dispatching the request server-side is
> relatively trivial once you have the decoded RPCRequest.
> The point of all this is of course to have all your requests one through a
> single servlet, which would, among other things, probably make collecting
> information about requests a little easier.
> -Kelsey
> --
> You received this message because you are subscribed to the Google Groups
> "Google Web Toolkit" group.
> To post to this group, send email to
> To unsubscribe from this group, send email to
> For more options, visit this group at

You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to
To unsubscribe from this group, send email to
For more options, visit this group at

No comments:

Post a Comment