I wonder how to change gwtp behaviour.
When I start gwt app (enter app url in browser) it always displays for me default place
. But when I enter url as follow: localhost/app#settings
gwtp should open place Settings
, but unfortunatelly it displays me Default
place.
Url in web browser address points to Settings
but the view is from default
place.
I would like to gwtp display for me the view from url.
Here is my configuration:
public class UiModule extends AbstractGinModule {
@Override
protected void configure() {
bind(AppView.Binder.class).in(Singleton.class);
bind(Footer.Binder.class).in(Singleton.class);
bind(GatekeeperProtectedMenuPanel.Binder.class).in(Singleton.class);
install(new GinFactoryModuleBuilder().build(MenuEntryFactory.class));
}
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);
// Load and inject CSS resources
bind(ResourceLoader.class).asEagerSingleton();
}
}
public class AppModule extends AbstractPresenterModule {
@Override
protected void configure() {
install(new UiModule());
// Application Presenters
bindPresenter(AppPresenter.class, AppPresenter.MyView.class, AppView.class, AppPresenter.MyProxy.class);
bindPresenter(HomePresenter.class, HomePresenter.MyView.class, HomeView.class, HomePresenter.MyProxy.class);
bindPresenter(ErrorPresenter.class, ErrorPresenter.MyView.class, ErrorView.class, ErrorPresenter.MyProxy.class);
bindPresenter(TestPresenter.class, TestPresenter.MyView.class, TestView.class, TestPresenter.MyProxy.class);
bindPresenter(PagePresenter.class, PagePresenter.MyView.class, PageView.class, PagePresenter.MyProxy.class);
bindPresenter(SettingsPresenter.class, SettingsPresenter.MyView.class, SettingsView.class, SettingsPresenter.MyProxy.class);
bindPresenter(FilesPresenter.class, FilesPresenter.MyView.class, FilesView.class, FilesPresenter.MyProxy.class);
bindPresenter(AdminAreaPresenter.class, AdminAreaPresenter.MyView.class, AdminAreaView.class, AdminAreaPresenter.MyProxy.class);
bindPresenter(LoginPresenter.class, LoginPresenter.MyView.class, LoginView.class, LoginPresenter.MyProxy.class);
}
}
This happens when I have GateKeeper
on place's presenter.
Here is code:
public class UserLoginGatekeeper extends UserLoginModel implements Gatekeeper {
private final CurrentUser currentUser;
@Inject
UserLoginGatekeeper(CurrentUser currentUser) {
this.currentUser = currentUser;
}
@Override
public boolean canReveal() {
return currentUser.isLoggedIn();
}
}
In my main app presenter I execute asynhronous call to server to check is user login. If so I set client variable currentUser.setLoggedIn(true);
. Base on this Gatekeeper
allow access to restricted part of app.
I think the problem is that my asynhronous call is triggered to late. And GWTP redirect to default place.
Here is my app presenter code:
public class AppPresenter extends TabContainerPresenter<AppPresenter.MyView, AppPresenter.MyProxy> implements AppUiHandlers, CurrentUserChangedHandler, AsyncCallStartHandler, AsyncCallFailHandler,
AsyncCallSucceedHandler {
@ProxyStandard
public interface MyProxy extends Proxy<AppPresenter> {
}
public interface MyView extends TabView, HasUiHandlers<AppUiHandlers> {
void refreshTabs();
void setTopMessage(String string);
void setLoginButtonVisbility(boolean isVisible);
}
@RequestTabs
public static final Type<RequestTabsHandler> SLOT_REQUEST_TABS = new Type<>();
@ChangeTab
public static final Type<ChangeTabHandler> SLOT_CHANGE_TAB = new Type<>();
public static final NestedSlot SLOT_TAB_CONTENT = new NestedSlot();
private static final LoginService service = GWT.create(LoginService.class);
private final PlaceManager placeManager;
private final CurrentUser currentUser;
@Inject
AppPresenter(EventBus eventBus, MyView view, MyProxy proxy, PlaceManager placeManager, CurrentUser currentUser) {
super(eventBus, view, proxy, SLOT_TAB_CONTENT, SLOT_REQUEST_TABS, SLOT_CHANGE_TAB, RevealType.Root);
this.placeManager = placeManager;
this.currentUser = currentUser;
getView().setUiHandlers(this);
onStart();
}
protected void onStart() {
service.isCurrentUserLoggedIn(new MethodCallback<Boolean>() {
@Override
public void onFailure(Method method, Throwable exception) {
MaterialToast.fireToast("Fail to check is current user logged in " + method + " " + exception.getLocalizedMessage());
}
@Override
public void onSuccess(Method method, Boolean response) {
currentUser.setLoggedIn(response);
getView().setLoginButtonVisbility(response);
}
});
};
@ProxyEvent
@Override
public void onCurrentUserChanged(CurrentUserChangedEvent event) {
getView().refreshTabs();
}
@ProxyEvent
@Override
public void onAsyncCallStart(AsyncCallStartEvent event) {
getView().setTopMessage("Loading...");
}
@ProxyEvent
@Override
public void onAsyncCallFail(AsyncCallFailEvent event) {
getView().setTopMessage("Oops, something went wrong...");
}
@ProxyEvent
@Override
public void onAsyncCallSucceed(AsyncCallSucceedEvent event) {
getView().setTopMessage(null);
}
@Override
public void onLogoutButtonClick() {
service.logout(new MethodCallback<Void>() {
@Override
public void onFailure(Method method, Throwable exception) {
MaterialToast.fireToast("Fail to logout " + method + " " + exception.getLocalizedMessage());
}
@Override
public void onSuccess(Method method, Void response) {
MaterialToast.fireToast("You have been Succefully logout");
PlaceRequest request = new PlaceRequest.Builder(placeManager.getCurrentPlaceRequest()).nameToken(Routing.Url.login).build();
placeManager.revealPlace(request);
currentUser.setLoggedIn(false);
getView().setLoginButtonVisbility(false);
}
});
}
}
Working solution:
/**
*
*/
package pl.korbeldaniel.cms.client.gin;
import gwt.material.design.client.ui.MaterialToast;
import org.fusesource.restygwt.client.Method;
import org.fusesource.restygwt.client.MethodCallback;
import pl.korbeldaniel.cms.client.place.Routing;
import pl.korbeldaniel.cms.client.security.CurrentUser;
import pl.korbeldaniel.cms.client.service.LoginService;
import com.google.gwt.core.shared.GWT;
import com.google.inject.Inject;
import com.gwtplatform.mvp.client.Bootstrapper;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.shared.proxy.PlaceRequest;
/**
* @author korbeldaniel
*
*/
public class MyBootstrapper implements Bootstrapper {
private final PlaceManager placeManager;
private final CurrentUser currentUser;
private static final LoginService service = GWT.create(LoginService.class);
@Inject
public MyBootstrapper(PlaceManager placeManager, CurrentUser currentUser) {
this.placeManager = placeManager;
this.currentUser = currentUser;
}
@Override
public void onBootstrap() {
GWT.log("OnBootstrap");
service.isCurrentUserLoggedIn(new MethodCallback<Boolean>() {
@Override
public void onFailure(Method method, Throwable exception) {
MaterialToast.fireToast("Fail to check is current user logged in " + method + " " + exception.getLocalizedMessage());
placeManager.revealErrorPlace("Fail to check is current user logged in " + method + " " + exception.getLocalizedMessage());
}
@Override
public void onSuccess(Method method, Boolean response) {
// MaterialToast.fireToast("1Current user is logged in: " +
// response);
currentUser.setLoggedIn(response);
if (response == true) {
placeManager.revealCurrentPlace();
} else {
placeManager.revealPlace(new PlaceRequest.Builder().nameToken(Routing.Url.login).build());
}
}
});
};
}
Yeah, your backend call is asynchronous and most likely the UserLoginGatekeeper
code will run before the backend call returns and the user gets redirected to the default page.
There are two solutions:
Use a dynamically generated host page (index.html) and set a javascript variable to the user details by the backend. You can read out the userdetails in a custom Bootstraper implementation and set the CurrentUser
.
If you don't want to use a dynamically generated host page, you can also move the backend call isCurrentUserLoggedIn
intot he custom Bootstrapper
implementation and in the onSuccess
callback reveal the first page (like in the above linked GWTP documentation)