How to properly set the Default Dispatcher with GIN?

646 views
Skip to first unread message

Benjamin Makus

unread,
Nov 15, 2012, 6:50:23 PM11/15/12
to rest...@googlegroups.com
Hi,

I'm using GWT 2.5.0, GIN 2.0, resty-gwt 1.4-SNAPSHOT and gwt-platform 0.7.


I just tried to use DefaultFilterawareDispatcher with XSRFTokenDispatcherFilter as resty-gwts default dispatcher. At the moment I set my default dispatcher inside the static-block of my EntryPoint class. It looks ugly, but seems to be the only way that works correctly:
public class MyApplication implements EntryPoint {
static {
Defaults.setServiceRoot(Config.REST_BASE_URL);
Defaults.setDispatcher(new MyDispatcher());
}
private final MyGinjector ginjector = GWT.create(MyGinjector.class);
public void onModuleLoad() {
DelayedBindRegistry.bind(ginjector);
ginjector.getPlaceManager().revealCurrentPlace();
}
}

Now I tried to clean my code a bit, using more of GIN. But I can't find a way to handle the resty-gwt initialization, because at application startup one of my Presenters makes a request using resty-gwt. If I use ginjector.getDispatcher() as the first statement in my onModuleLoad() method the request always fails because of the missing CSRF Token. It seems like the whole gwt-presenter stuff gets loaded on GWT.create(MyGinjector.class); so that I have no chance to set resty-gwt's default dispatcher before any presenter can make a request.


How do you guys work with resty-gwt and GIN?

Benjamin Makus

unread,
Nov 15, 2012, 6:56:17 PM11/15/12
to rest...@googlegroups.com
My files (excerpts):

@GinModules({ GwtpModule.class, RestModule.class })
public interface MyGinjector extends Ginjector {
DefaultFilterawareDispatcher getDispatcher();
PlaceManager getPlaceManager();
EventBus getEventBus();
Provider<MainPagePresenter> getMainPagePresenter();

// ...
}



public class GwtpModule extends AbstractPresenterModule {
@Override
protected void configure() {
install(new DefaultModule(MyPlaceManager.class));

bindPresenter(MainPagePresenter.class, MainPagePresenter.MyView.class,
MainPageView.class, MainPagePresenter.MyProxy.class);

// ...
}
}





public class RestModule extends AbstractGinModule {
@Override
protected void configure() {}
@Provides @Singleton
public FilterawareDispatcher provideFilterAwareDispatcher() {
XSRFToken x = new XSRFToken();
x.setToken("thisIsATest");
return new DefaultFilterawareDispatcher(new XSRFTokenDispatcherFilter(x));
}
@Provides @Singleton
public AnchorService provideAnchorService() {
return GWT.create(AnchorService.class);
}
@Provides @Singleton
public ExperimentService provideExperimentService() {
return GWT.create(ExperimentService.class);
}
// ...
}

Johannes Barop

unread,
Nov 16, 2012, 10:28:05 AM11/16/12
to rest...@googlegroups.com
Hi,

I put all that Dispatcher stuff into a separate class which is responsible for setting up the dispatcher and does Defaults.setXXX stuff.

/**
 * The application's custom Resty {@link Dispatcher} setup.
 * 
 * <p>
 * Bind it with {@link GinScopedBindingBuilder#asEagerSingleton()} because it should never be
 * initialized lazy and should be bound before any other service/resty stuff gets executed.
 * </p>
 * 
 * @author <a href="mailto:jb@barop.de">Johannes Barop</a>
 * 
 */
public final class RestyDispatcher extends DefaultFilterawareDispatcher {

  /**
   * Provides the {@link RestyDispatcher} and set it as default Resty {@link Dispatcher}.
   */
  public static class Provider implements com.google.inject.Provider<Dispatcher> {
    @Override
    public Dispatcher get() {
      Dispatcher dispatcher = new RestyDispatcher();
      Defaults.setDispatcher(dispatcher);
      return dispatcher;
    }
  }

  /**
   * Dispatcher configuration.
   * 
   * <p>
   * Use the {@link #defaultDispatcherFilter} to create a {@link Dispatcher}.
   * </p>
   * 
   * <p>
   * This is encapsulated here for the sake of readability and because Java cannot reference
   * instance variables in the constructor.
   * </p>
   */
  private static final class DispatcherConfig {
    final CallbackFactory callbackFactory = new DefaultCallbackFactory();
    final DispatcherFilter defaultDispatcherFilter = new DefaultDispatcherFilter(callbackFactory);
  }

  /**
   * Hidden Constructor.
   * 
   * Instances of this class should only generated by {@link Provider#get()}.
   */
  private RestyDispatcher() {
    super(new DispatcherConfig().defaultDispatcherFilter);
  }

}


You have to bind it as eager Singleton:
    bind(Dispatcher.class).toProvider(RestyDispatcher.Provider.class).asEagerSingleton();


Cheers,
Johannes

kristian

unread,
Nov 16, 2012, 10:57:40 AM11/16/12
to rest...@googlegroups.com
with Gin and the default dispatcher there is a timing problem: first
the Defaults.setDispatcher must be called before creating any instance
of Resource or RestService. that issue got addressed (partially) on
master branch.

- Kristian

Benjamin Makus

unread,
Nov 17, 2012, 6:40:00 PM11/17/12
to rest...@googlegroups.com, m.kri...@web.de
Yeah, you're right: "Just" a timing problem.

What do you mean with "[...] on master branch". Where exactly was this issue addressed. And how?
I'm already using resty-gwt 1.4-SNAPSHOT. Or do you mean some special methods to call or special syntax to use?

kristian

unread,
Nov 18, 2012, 2:41:18 AM11/18/12
to Benjamin Makus, rest...@googlegroups.com
actually I meant to grab the sources from github and compile it yourself.

but I just pushed a fix for the RestService generators to address the
dispatcher here correctly. since there are no tests for that
dispatcher problem so if it works for you. I pushed a
restygwt-1.4-SNAPSHOT to my personal repo

http://mojo.saumya.de/

please report whether it works now for you.

- Kristian

Benjamin Makus

unread,
Nov 18, 2012, 9:14:08 AM11/18/12
to rest...@googlegroups.com, Benjamin Makus, m.kri...@web.de
So i'll grab 
restygwt-1.4-20121118.073434-3.jar 
from you repo.
And now what have I exactly to do, to initialize resty-gwt with GIN before(!) gwt-platform?

Implement a Provider class as in Johannes Barop's posting?


Hiram Chirino

unread,
Nov 18, 2012, 9:59:07 AM11/18/12
to restygwt
I've finally setup a nightly deployment job on our CI box.  So restygwt should have fresh nightly snapshots deployed to:
--

Hiram Chirino

Engineering | Red Hat, Inc.

hchi...@redhat.com | fusesource.com | redhat.com

skype: hiramchirino | twitter: @hiramchirino

blog: Hiram Chirino's Bit Mojo


Benjamin Makus

unread,
Nov 18, 2012, 4:23:03 PM11/18/12
to rest...@googlegroups.com, hi...@hiramchirino.com
I've tried kristian's build with
@Singleton @Provides
public Dispatcher getDispatcher() {
    DefaultFilterawareDispatcher dfd = new DefaultFilterawareDispatcher();
    // i've added here some dispatchers to dfd
    return dfd;
}
in MyModule class

and
Provider<Dispatcher> getDispatcher();
in MyGinjector class

but nothing changed: My Presenter still makes its request using resty-gwt without those filters (If I make this request a second time using a Button, the dispatchers get called)

kristian

unread,
Nov 18, 2012, 4:48:39 PM11/18/12
to Benjamin Makus, rest...@googlegroups.com


On Sun, Nov 18, 2012 at 7:44 PM, Benjamin Makus <benn...@gmail.com> wrote:
Implement a Provider class as in Johannes Barop's posting?

yes, the provider setting the Defaults is a good idea and binding it asEagerSingleton should set the dispatcher **before** you use any RestService.

- Kristian

Benjamin Makus

unread,
Nov 18, 2012, 5:25:29 PM11/18/12
to rest...@googlegroups.com, Benjamin Makus, m.kri...@web.de
It still doesn't work! I just copied the code from Johannes Barop...

My setup:

1. Ginjector creates an EagerSingleton of CurrentUser
2. CurrentUser processes the Login inside its constuctor
3. Ginjector creates an instance of RestyDispatcher

It doesn't matter if I put bind(Dispatcher.class)...asEagerSingleton() or bind(CurrentUser.class) at the top of my Gin Module file. 

kristian

unread,
Nov 19, 2012, 12:55:20 AM11/19/12
to Benjamin Makus, rest...@googlegroups.com
you need the Dispatcher (indirectly) inside the constructor of
CurrentUser. I do not think that GIN guarantees that the
DispatcherConfig got already instantiated.

IMO the constructor should do only the wire up of the component and
avoid any http requests or alike.

since the CurrentUser needs to carry state (login succeeded or failed)
it is better to have a login method which you use inside
MyEntryPoint#onModuleLoad(). for this you need to expose the
CurrentUser via Ginjector but then a eager singleton DispatcherConfig
is already in place and did set Defaults.setDispatcher as needed.

the latest patch of mine just guarantees that in whatever order GIN
instantiates the components the RestService uses the right default
(assuming the DispatcherConfig component is eagerly instantiated -
lazy will only work when you get the singleton via ginjector before
using any other components).

hope things get a bit clearer . . .

Kristian

Benjamin Makus

unread,
Nov 19, 2012, 7:20:22 AM11/19/12
to rest...@googlegroups.com, Benjamin Makus, m.kri...@web.de
Thank you!

This works (for setDispatcher), and shows up a new problem:

EntryPoint:
public class PostGISgwt implements EntryPoint {
private final MyGinjector ginjector = GWT.create(MyGinjector.class);

public void onModuleLoad() {
initRestyGwt();
ginjector.getCurrentUser().fetchUser();

DelayedBindRegistry.bind(ginjector);
ginjector.getPlaceManager().revealCurrentPlace();
}
private void initRestyGwt() {
Defaults.setServiceRoot(Config.REST_BASE_URL);
Defaults.setDispatcher(new CSRFTokenDispatcher());
}
}



The setServiceRoot method doesn't work :(

kristian

unread,
Nov 19, 2012, 8:05:33 AM11/19/12
to Benjamin Makus, rest...@googlegroups.com
:)

I will have a look . . .

Benjamin Makus

unread,
Nov 20, 2012, 5:22:03 AM11/20/12
to rest...@googlegroups.com, Benjamin Makus, m.kri...@web.de
While waiting for kristian's answer, I'd like to give you my nice solution for the XSRFTokenDispatcherFilter using GIN:

With GIN I create 3 singletons:
1. XSRFToken
2. XSRFTokenDispatcherFilter
3. DefaultFilterawareDispatcher

public class RestModule extends AbstractGinModule {
@Override
protected void configure() {}
@Provides @Singleton
public XSRFToken provideXSRFToken() {
XSRFToken xsrfToken = new XSRFToken();

// get the CSRF token from the HTML document and initialize the XSRFToken
NodeList<MetaElement> metaTags = Document.get().getElementsByTagName(MetaElement.TAG).cast();
for(int i=0; i<metaTags.getLength(); i++) {
if(metaTags.getItem(i).getName().equals(Config.RAILS_CSRF_TOKEN_META_TAG_NAME)) {
xsrfToken.setToken(metaTags.getItem(i).getContent());
break;
}
}
return xsrfToken;
}
@Provides @Singleton @Inject
public XSRFTokenDispatcherFilter provideXSRFTokenDispatcherFilter(XSRFToken xsrf) {
return new XSRFTokenDispatcherFilter(xsrf);
}
@Provides @Singleton
public FilterawareDispatcher provideDispatcher() {
return new DefaultFilterawareDispatcher();
}
}

The XSRFToken is getting initialized within its provider. As I'm using Rails, I fetch the token from the HTML document.
Next XSRFTokenDispatcherFilter needs an instance of XSRFToken in its constructor, so I simply inject it.
The last one is the FilterawareDispatcher provider. I know that GIN is unnecessary here, but I wanted to keep it all in one place ;-)



So next let's have a look at the Ginjector:
@GinModules({ RestModule.class })
public interface MyGinjector extends Ginjector {
XSRFTokenDispatcherFilter getXSRFTokenDispatcherFilter();
FilterawareDispatcher getFilterawareDispatcher();
}

I need those two, because I have to add the XSRFDispatcherFilter to the FilterawareDispatcher within my applications EntryPoint. I don't need the XSRFToken, 'cause it's already set for the XSRFTokenDispatcherFilter.

So here's my EntryPoint:
public class PostGISgwt implements EntryPoint {
private final MyGinjector ginjector = GWT.create(MyGinjector.class);

public void onModuleLoad() {
initRestyGwt();
}
private void initRestyGwt() {
FilterawareDispatcher filterawareDispatcher = ginjector.getFilterawareDispatcher();
filterawareDispatcher.addFilter(ginjector.getXSRFTokenDispatcherFilter());
Defaults.setDispatcher(filterawareDispatcher);
}
}



If we have to change the XSRF token at some point, we simply inject it and call setToken(String token).
Here's an example for gwt-platform, where I receive a new CSRF token on sign out (the onSignOut method get's called by the View when the user clicks the sign out button):
public class SignOutPresenterWidget
extends PresenterWidget<SignOutPresenterWidget.MyView>
implements SessionUiHandlers {

public interface MyView extends View, HasUiHandlers<SessionUiHandlers> {}
@Inject SessionService sessionService;
@Inject XSRFToken xsrfToken;
@Inject
public SignOutPresenterWidget(EventBus eventBus, MyView view) {
super(eventBus, view);
getView().setUiHandlers(this);
}
@Override
public void onSignOut() {
sessionService.signOut(new MethodCallback<SignOutResponse>() {
@Override
public void onSuccess(Method method, SignOutResponse response) {
xsrfToken.setToken(response.getCsrfToken());
}
@Override
public void onFailure(Method method, Throwable exception) {
// display an error message
}
});
}
}


Maybe someone is interested in this kind of solution ;-)

(I'll have a look at XSRFTokenCallbackFilter, maybe this could make the "set token on sign out" a little bit easier ?!)

Cheers!

kristian

unread,
Nov 20, 2012, 7:31:31 AM11/20/12
to Benjamin Makus, rest...@googlegroups.com
that is a bigger thing but why not do something what I do in my
EntryPoint of projects:

public void onModuleLoad() {
Defaults.setServiceRoot(GWT.getModuleBaseURL().replaceFirst("[a-zA-Z0-9_]+/$",
""));

Benjamin Makus

unread,
Nov 20, 2012, 8:01:01 AM11/20/12
to rest...@googlegroups.com, Benjamin Makus, m.kri...@web.de
Why? Simply because it doesn't work for me ... I don't know why.
Here's my EntryPoint (works):
public class PostGISgwt implements EntryPoint {
static {
Defaults.setServiceRoot(Config.REST_BASE_URL);
}
private final MyGinjector ginjector = GWT.create(MyGinjector.class);

public void onModuleLoad() {
initRestyGwt();

ginjector.getCurrentUser().fetchUser();
DelayedBindRegistry.bind(ginjector);
ginjector.getPlaceManager().revealCurrentPlace();
}
private void initRestyGwt() {
FilterawareDispatcher filterawareDispatcher = ginjector.getFilterawareDispatcher();
filterawareDispatcher.addFilter(ginjector.getXSRFTokenDispatcherFilter());
filterawareDispatcher.addFilter(ginjector.getXSRFTokenCallbackDispatcherFilter());
Defaults.setDispatcher(filterawareDispatcher);
}
}


But this doesn't work:
public class PostGISgwt implements EntryPoint {
private final MyGinjector ginjector = GWT.create(MyGinjector.class);

public void onModuleLoad() {
Defaults.setServiceRoot(Config.REST_BASE_URL);
initRestyGwt();

ginjector.getCurrentUser().fetchUser();
DelayedBindRegistry.bind(ginjector);
ginjector.getPlaceManager().revealCurrentPlace();
}
private void initRestyGwt() {
FilterawareDispatcher filterawareDispatcher = ginjector.getFilterawareDispatcher();
filterawareDispatcher.addFilter(ginjector.getXSRFTokenDispatcherFilter());
filterawareDispatcher.addFilter(ginjector.getXSRFTokenCallbackDispatcherFilter());
Defaults.setDispatcher(filterawareDispatcher);
}
}


And this is my Config class:
public class Config {
public static final String RAILS_CSRF_TOKEN_HTTP_HEADER_NAME = "X-Csrf-Token";
public static final String RAILS_CSRF_TOKEN_META_TAG_NAME = "csrf-token";
public static final String REST_BASE_URL = GWT.getHostPageBaseURL();
}



I've looked inside resty-gwt's source code:

private static String serviceRoot = GWT.getModuleBaseURL();


Isn't it strange that MY GWT.getModuleBaseURL() differs from resty-gwt's one?!


Maybe you can imagine why this happens. I just can't...

Benjamin Makus

unread,
Nov 20, 2012, 8:03:20 AM11/20/12
to rest...@googlegroups.com, Benjamin Makus, m.kri...@web.de
Just ignore the last 5 lines :-D
There's a difference between GWT.getModuleBaseURL() and  GWT.getHostPageBaseURL()

kristian

unread,
Nov 20, 2012, 8:16:25 AM11/20/12
to Benjamin Makus, rest...@googlegroups.com
the reason why it works for me is that I create the Ginjector after
setting the ServieRoot:

public void onModuleLoad() {
Defaults.setServiceRoot(GWT.getModuleBaseURL().replaceFirst("[a-zA-Z0-9_]+/$",
""));
Defaults.setDispatcher(DefaultDispatcherSingleton.INSTANCE);
GWT.log("base url for restservices: " + Defaults.getServiceRoot());

final TranslationsGinjector injector =
GWT.create(TranslationsGinjector.class);

I will have a look how to make that thing lazy BUT not sure if that is so easy.

- Kristian

Benjamin Makus

unread,
Nov 20, 2012, 8:35:20 AM11/20/12
to rest...@googlegroups.com, Benjamin Makus, m.kri...@web.de
That sounds like an acceptable solution to me:

public void onModuleLoad() {
Defaults.setServiceRoot(Config.REST_BASE_URL);

// IMPORTANT: The ginjector has to be set AFTER resty-gwt's serviceRoot
final MyGinjector ginjector = GWT.create(MyGinjector.class);

FilterawareDispatcher filterawareDispatcher = ginjector.getFilterawareDispatcher();
filterawareDispatcher.addFilter(ginjector.getXSRFTokenDispatcherFilter());
filterawareDispatcher.addFilter(ginjector.getXSRFTokenCallbackDispatcherFilter());
Defaults.setDispatcher(filterawareDispatcher);
ginjector.getCurrentUser().fetchUser();
DelayedBindRegistry.bind(ginjector);
ginjector.getPlaceManager().revealCurrentPlace();
}

kristian

unread,
Nov 20, 2012, 8:41:55 AM11/20/12
to rest...@googlegroups.com, Benjamin Makus
please file an issue so we can fix it for the next release and get
restygwt overall more GIN friendly ;) - thanx

Benjamin Makus

unread,
Nov 20, 2012, 9:17:33 AM11/20/12
to rest...@googlegroups.com, Benjamin Makus, m.kri...@web.de
Reply all
Reply to author
Forward
0 new messages