I was digging around GWT a little this week and found a neat way to append information to server requests sent by gwt-dispatch. By default, dispatch requests show up in the logs as just “/your_app_path/dispatch”. But it turns out you can add a few lines to your DispatchAsync class to append the action name, so you see “/your_app_path/dispatch/SomeAction” in the server logs.
This is really cool on AppEngine because the Dashboard aggregates the number of requests and total CPU for each URL. With the basic dispatcher, all requests to “/your_app_path/dispatch” get rolled up together, but with this enhancement, you get dashboard roll-ups for each Action.
All you need is a couple extra lines in StandardDispatchAsync. In addition, you must append a wildcard to your dispatch servlet mapping in web.xml, “/your_app_path/dispatch/*” (thanks to Ben Binford for pointing this out). The changes from gwt-dispatch are in lines 27 and 35-38.
package net.customware.gwt.dispatch.client.standard; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.ServiceDefTarget; import net.customware.gwt.dispatch.client.AbstractDispatchAsync; import net.customware.gwt.dispatch.client.DispatchAsync; import net.customware.gwt.dispatch.client.ExceptionHandler; import net.customware.gwt.dispatch.server.Dispatch; import net.customware.gwt.dispatch.shared.Action; import net.customware.gwt.dispatch.shared.Result; /** * This class is based on the default implementation of {@link DispatchAsync}, which is * essentially the client-side access to the {@link Dispatch} class on the * server-side. * * This version appends the name of the Action class to the URL as extra path info. * * @author David Peterson * @author David Chandler */ public class StandardDispatchAsync extends AbstractDispatchAsync { private static final StandardDispatchServiceAsync realService = GWT.create( StandardDispatchService.class ); private static final String baseUrl = ((ServiceDefTarget)realService).getServiceEntryPoint() + "/"; public StandardDispatchAsync( ExceptionHandler exceptionHandler ) { super( exceptionHandler ); } public <A extends Action<R>, R extends Result> void execute( final A action, final AsyncCallback<R> callback ) { // Append action class name as extra path info String className = action.getClass().getName(); int namePos = className.lastIndexOf(".") + 1; className = className.substring(namePos); ((ServiceDefTarget)realService).setServiceEntryPoint(baseUrl + className); realService.execute( action, new AsyncCallback<Result>() { public void onFailure( Throwable caught ) { StandardDispatchAsync.this.onFailure( action, caught, callback ); } @SuppressWarnings({"unchecked"}) public void onSuccess( Result result ) { StandardDispatchAsync.this.onSuccess( action, (R) result, callback ); } } ); } }
There are other possible uses of the extra path info. See this forum thread for discussion of security uses and the corresponding warnings.
Enjoy!