javagwtdependency-injectiongwtpgwt-platform

Other way to achive GWTP placeManager than Constructor's @Inject annotation


I use GWTP and restyGWT. I would like to use placeManager in restyGWT DispatcherCallback, when my rest server will answer with 401 unauthorised I would like to redirect application to login page, that User could apply credentials and retried his request.

To do this I have to somehow get instance of PlaceManager (from gwtp framework). I cannot use @Inject annotation, cause I have manuall call to constructor as follow:

public class ForbiddenDispatcherFilter implements DispatcherFilter {
    @Override
    public boolean filter(Method method, RequestBuilder builder) {
        builder.setCallback(new ForbiddenDispatcherCallback(method));
        return true;
    }
}


public class ForbiddenDispatcherCallback implements RequestCallback {
    protected RequestCallback requestCallback;

    public ForbiddenDispatcherCallback(Method method) {
        this.requestCallback = method.builder.getCallback();
    }

    @Override
    public void onResponseReceived(Request request, Response response) {
    if (response.getStatusCode() == Response.SC_FORBIDDEN || response.getStatusCode() == Response.SC_UNAUTHORIZED) {
        // make a hard redirect to login page
        // TODO change redirect to GWTP native
        Window.Location.assign("#login");
        // PlaceRequest placeRequest = new
        // PlaceRequest.Builder(placeManager.getCurrentPlaceRequest()).nameToken(Routing.Url.login).build();
        // placeManager.revealPlace(placeRequest);
    } else {
        requestCallback.onResponseReceived(request, response);
    }

}


public class RestyDispatcher extends DefaultFilterawareDispatcher {

    public RestyDispatcher() {
    addFilter(new ForbiddenDispatcherFilter());
    addFilter(new BasicAuthHeaderDispatcherFilter());
    }

    @Override
    public Request send(Method method, RequestBuilder builder) throws RequestException {
    return super.send(method, builder);
    }
}

Please help.


Edit

public class ClientModule extends AbstractPresenterModule {
    @Override
    protected void configure() {
    bind(RestyGwtConfig.class).asEagerSingleton();

    install(new DefaultModule.Builder()//
        .defaultPlace(Routing.HOME.url)//
        .errorPlace(Routing.ERROR.url)//
        .unauthorizedPlace(Routing.LOGIN.url)//
        .tokenFormatter(RouteTokenFormatter.class).build());
    install(new AppModule());
    // install(new
    // GinFactoryModuleBuilder().build(AssistedInjectionFactory.class));

    bind(CurrentUser.class).in(Singleton.class);
    bind(IsAdminGatekeeper.class).in(Singleton.class);
    bind(UserLoginGatekeeper.class).in(Singleton.class);

    // Google Analytics
    // bindConstant().annotatedWith(GaAccount.class).to("UA-8319339-6");

    // Load and inject CSS resources
    bind(ResourceLoader.class).asEagerSingleton();

    }

}

and:

public class RestyGwtConfig {

    static {

    // GWT.log("--> RestyGwtConfig -> setDispatcher");
    Defaults.setDispatcher(new RestyDispatcher());

    // GWT.log("--> RestyGwtConfig -> setServiceRoot");
    Defaults.setServiceRoot(new Resource(GWT.getModuleBaseURL()).resolve(ServiceRouting.SERVICE_ROOT).getUri());
    UserCredentials.INSTANCE.setUserName("ronan");
    UserCredentials.INSTANCE.setPassword("password");
    }

}

Solution

  • How and where do you create your ForbiddenDispatcherFilter ?

    You could use guice's AssistedInjection to inject the PlaceManager into your ForbiddenDispatcherCallback.

    public class ForbiddenDispatcherCallback implements RequestCallback {
        protected RequestCallback requestCallback;
        protected PlaceManager placeManager;
    
        @Inject
        public ForbiddenDispatcherCallback(PlaceManager placeManager, @Assisted Method method) {
            this.placeManager = placeManager;
            this.requestCallback = method.builder.getCallback();
        }
    }
    

    You need to define an factory interface:

    public interface AssistedInjectionFactory {
        ForbiddenDispatcherCallback createForbiddenCallback(Method method);
    }
    

    In the configure method of your ClientModule you need to call:

    install(new GinFactoryModuleBuilder().build(AssistedInjectionFactory.class));
    

    Then you can instantiate your class this way:

    public class ForbiddenDispatcherFilter implements DispatcherFilter {
        AssistedInjectionFactory factory;
    
        @Inject
        public ForbiddenDispatcherFilter(AssistedInjectionFactory factory) 
        {
            this.factory = factory;
        }
    
        @Override
        public boolean filter(Method method, RequestBuilder builder) {
            builder.setCallback(factory.AssistedInjectionFactory(method)) 
            return true;
        }
    }
    

    Of course this requires that you also inject the ForbiddenDispatcherFilter.

    Edit:

    You could try to pass the RestyDispatcher to the constructor of your RestyGWTConfig:

    public class RestyGwtConfig {
    
        @Inject
        public RestyGwtConfig(RestyDispatcher dispatcher) {
            Defaults.setDispatcher(dispatcher);
        }
    
        static {
        // GWT.log("--> RestyGwtConfig -> setServiceRoot");
        Defaults.setServiceRoot(new Resource(GWT.getModuleBaseURL()).resolve(ServiceRouting.SERVICE_ROOT).getUri());
        UserCredentials.INSTANCE.setUserName("ronan");
        UserCredentials.INSTANCE.setPassword("password");
        }
    }
    

    The RestyDispatcher looks like this:

    public class RestyDispatcher extends DefaultFilterawareDispatcher {
    
        @Inject
        public RestyDispatcher(ForbiddenDispatcherFilter filter) {
          addFilter(filter);
          addFilter(new BasicAuthHeaderDispatcherFilter());
        }
    
        @Override
        public Request send(Method method, RequestBuilder builder) throws RequestException {
          return super.send(method, builder);
        }
    }