Append additional info to dispatch request for logs

35 views
Skip to first unread message

David Chandler

unread,
Mar 12, 2010, 3:18:10 PM3/12/10
to GWT Presenter
In order to make request logs more beneficial, it would be helpful to
append the Action classname to the service URL. This info is ignored
by the dispatch servlet. I've added 3 lines to my copy of
StandardDispatchAsync to demonstrate:

...
import com.google.gwt.user.client.rpc.ServiceDefTarget;
...
public class StandardDispatchAsync extends AbstractDispatchAsync {

private static final StandardDispatchServiceAsync realService =
GWT.create( StandardDispatchService.class );
// NEW
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 ) {
// NEW Append extra path info for logs
((ServiceDefTarget)realService).setServiceEntryPoint(baseUrl +
action.getClass().getSimpleName());

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 );
}
} );
}


}

Previously, my request logs showed only
/app/dispatch

whereas now they show
/app/dispatch?SomeAction

Is this useful to anyone else? Is it worth making standard behavior?

/dmc
http://turbomanage.wordpress.com

Stephen Haberman

unread,
Mar 12, 2010, 3:24:04 PM3/12/10
to gwt-pr...@googlegroups.com

> Is this useful to anyone else? Is it worth making standard behavior?

Seems spiffy to me.

- Stephen

David Chandler

unread,
Mar 12, 2010, 3:30:08 PM3/12/10
to gwt-pr...@googlegroups.com
Oops, it doesn't quite work as written. Change class.getSimpleName()
to class.getName() and it works. Unfortunately, this results in full
package path, but a little substring work could fix that, too, if it
really matters.

/dmc

David Chandler

unread,
Mar 12, 2010, 3:36:33 PM3/12/10
to gwt-pr...@googlegroups.com
Yikes, it's worse than I thought. realService is static, so I need to
reset the entry point to the base after each call. I'll post back when
it really works...

/dmc

David Chandler

unread,
Mar 12, 2010, 3:51:02 PM3/12/10
to gwt-pr...@googlegroups.com
OK, got it. I was right before, just had forgotten to refresh my GWT app.

Here's the bit of substring code if desired:
// Append extra path info for logs
String className = action.getClass().getName();
int namePos = className.lastIndexOf(".") + 1;
className = className.substring(namePos);
((ServiceDefTarget)realService).setServiceEntryPoint(baseUrl +
className);

Sorry for all the noise, especially since I just realized I'm in the
wrong group, anyway. Will try again in gwt-dispatch.

Is it Friday yet?
/dmc

Ben Binford

unread,
Mar 12, 2010, 3:34:38 PM3/12/10
to gwt-pr...@googlegroups.com
If you made the url .../dispatch/command-name we could secure actions based on security-constraint and security-role in web.xml, which is pretty nice if your application maps to those concepts. You'll need to change the dispatch servlet mapping to dispatch/*, so maybe making the command names path components vs. query string components should be optional as well.

On Fri, Mar 12, 2010 at 3:30 PM, David Chandler <turbo...@gmail.com> wrote:

David Chandler

unread,
Mar 12, 2010, 11:32:34 PM3/12/10
to gwt-pr...@googlegroups.com
Thanks, Ben! This is exactly what I was looking for originally, but
was lacking the magic asterisk in the servlet mapping. By using extra
path info instead of the query string, not only can security be
applied, but also the AppEngine dashboard aggregates each dispatch
action separately for computing totals. Previously, all calls to
.../dispatch were aggregated together, so I would see 70% of total CPU
being spent on .../dispatch. Now it's broken down per action, which is
more insightful.

All I changed from the previous example was "?" to "/" and the servlet
mapping to ".../dispatch/*"

Thanks again,
/dmc
http://turbomanage.wordpress.com

Marcos Alcantara

unread,
Mar 13, 2010, 6:24:05 AM3/13/10
to gwt-pr...@googlegroups.com
Wowww!! That was really great!!!! =) =) =)

Thanks!!!

David Peterson

unread,
Mar 13, 2010, 9:29:14 AM3/13/10
to gwt-pr...@googlegroups.com
Pretty neat David. Do you have a complete final patch around?

David

David Chandler

unread,
Mar 13, 2010, 10:03:04 AM3/13/10
to gwt-pr...@googlegroups.com
Sure. Here it is for StandardDispatchAsync. (caveat: I've been testing
with my old AppEngineDispatchAsync, but I don't see any reason why it
wouldn't work the same way here). All you need to do to use it is to
append /* to your dispatch servlet mappping.

Index: StandardDispatchAsync.java
===================================================================
--- StandardDispatchAsync.java (revision 118)
+++ StandardDispatchAsync.java (working copy)
@@ -2,6 +2,8 @@

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;
@@ -19,12 +21,19 @@


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 );

David Chandler

unread,
Mar 13, 2010, 10:27:02 AM3/13/10
to gwt-pr...@googlegroups.com
Two more notes:

Depending on how you make this configurable, you should probably
include a comment about changing the dispatch servlet mapping. I'm a
little nervous about making it default behavior because I think it
would introduce confusion about how action handlers actually get
mapped: i.e., if I saw the action name in the logs, I might assume the
extra path info is used by the dispatch servlet to find the
appropriate ActionHandler.

Secondly, it is not safe to use the extra path info for security "as
is" because the extra path info in the HTTP request can be very, very
easily tampered (unlike the serialized Action class in the RPC, which
is probably possible, but harder). In order to allow this use safely,
we would need to modify StandardDispatchServlet to match the RPC
Action against the classname in the extra path info and throw an
exception if they don't match.

/dmc

Reply all
Reply to author
Forward
0 new messages