gwtgwtpgwt-platformpresenter

GWTP. How to get access from one presenter to another- they are not connected by slots mechanism


I have one presenter for login screen purpose. And I have AppPresenter for the whole application. Each view (except login) is displayed inside AppView slots.

In AppView I have logout button, which should be visible only when user is logged in, so when user logs in, the button is changing to visible. When user click on it to logout, the button should disappear.

For hiding it is simple, cause it happens in one view/presenter. But I have problem to do it for showing this button, after user login, cause it happens on other presenter/view.

I am new to gwtp, so please help me to resolve this issue.

How should I access other presenter from login one? They are not related! Would it be enough and good if I will just add the class of AppPresenter to LoginPresenter constructor with @Inject annotation? As follow:

@Inject
LoginPresenter(EventBus eventBus, MyView view, MyProxy proxy, CurrentUser currentUser, PlaceManager placeManager, AppPresenter appPresenter) {
    super(eventBus, view, proxy, RevealType.Root);
    this.currentUser = currentUser;
    if (!currentUser.isLoggedIn()) {
        placeManager.revealDefaultPlace();
    }
    this.placeManager = placeManager;
    this.appPresenter = appPresenter;
    getView().setUiHandlers(this);
    Window.setTitle(Routing.Name.login);
    editorDriver = getView().createEditorDriver();
    editorDriver.edit(model);
}



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(AdminAreaPresenter.class, AdminAreaPresenter.MyView.class, AdminAreaView.class, AdminAreaPresenter.MyProxy.class);

    bindPresenter(LoginPresenter.class, LoginPresenter.MyView.class, LoginView.class, LoginPresenter.MyProxy.class);

    }
}

Presenters:

package pl.daniel.cms.client.place.app;

import gwt.material.design.client.ui.MaterialToast;

import org.fusesource.restygwt.client.Method;
import org.fusesource.restygwt.client.MethodCallback;

import pl.daniel.cms.client.place.Routing;
import pl.daniel.cms.client.security.CurrentUser;
import pl.daniel.cms.client.security.CurrentUserChangedEvent;
import pl.daniel.cms.client.security.CurrentUserChangedHandler;
import pl.daniel.cms.client.service.LoginService;

import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.shared.GwtEvent.Type;
import com.google.inject.Inject;
import com.google.web.bindery.event.shared.EventBus;
import com.gwtplatform.mvp.client.ChangeTabHandler;
import com.gwtplatform.mvp.client.HasUiHandlers;
import com.gwtplatform.mvp.client.RequestTabsHandler;
import com.gwtplatform.mvp.client.TabContainerPresenter;
import com.gwtplatform.mvp.client.TabView;
import com.gwtplatform.mvp.client.annotations.ChangeTab;
import com.gwtplatform.mvp.client.annotations.ProxyEvent;
import com.gwtplatform.mvp.client.annotations.ProxyStandard;
import com.gwtplatform.mvp.client.annotations.RequestTabs;
import com.gwtplatform.mvp.client.presenter.slots.NestedSlot;
import com.gwtplatform.mvp.client.proxy.AsyncCallFailEvent;
import com.gwtplatform.mvp.client.proxy.AsyncCallFailHandler;
import com.gwtplatform.mvp.client.proxy.AsyncCallStartEvent;
import com.gwtplatform.mvp.client.proxy.AsyncCallStartHandler;
import com.gwtplatform.mvp.client.proxy.AsyncCallSucceedEvent;
import com.gwtplatform.mvp.client.proxy.AsyncCallSucceedHandler;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.client.proxy.Proxy;
import com.gwtplatform.mvp.shared.proxy.PlaceRequest;

/**
 * The main {@link com.gwtplatform.mvp.client.Presenter} of the application. It
 * contains a number of tabs allowing access to the various parts of the
 * application. Tabs are refreshed whenever the current user's privileges change
 * in order to hide areas that cannot be accessed.
 */
public class AppPresenter extends TabContainerPresenter<AppPresenter.MyView, AppPresenter.MyProxy> implements AppUiHandlers, CurrentUserChangedHandler, AsyncCallStartHandler, AsyncCallFailHandler,
    AsyncCallSucceedHandler {
    /**
     * {@link AppPresenter}'s proxy.
     */
    @ProxyStandard
    public interface MyProxy extends Proxy<AppPresenter> {
    }

    /**
     * {@link AppPresenter}'s view.
     */
    public interface MyView extends TabView, HasUiHandlers<AppUiHandlers> {
    void refreshTabs();

    void setTopMessage(String string);

    void setLoginButtonVisbility(boolean isVisible);
    }

    /**
     * This will be the event sent to our "unknown" child presenters, in order
     * for them to register their tabs.
     */
    @RequestTabs
    public static final Type<RequestTabsHandler> SLOT_REQUEST_TABS = new Type<>();

    /**
     * Fired by child proxie's when their tab content is changed.
     */
    @ChangeTab
    public static final Type<ChangeTabHandler> SLOT_CHANGE_TAB = new Type<>();

    /**
     * Use this in leaf presenters, inside their {@link #revealInParent} method.
     */
    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) {
        GWT.log(response.toString());
        // MaterialToast.fireToast("User login status: " + method + " "
        // + response.toString());
        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);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * pl.daniel.cms.client.place.app.AppUiHandlers#onLogoutButtonClick()
     */
    @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("Succefully logout " + method + " " + response);
        PlaceRequest request = new PlaceRequest.Builder(placeManager.getCurrentPlaceRequest()).nameToken(Routing.Url.login).build();
        placeManager.revealPlace(request);
        currentUser.setLoggedIn(false);
        getView().setLoginButtonVisbility(false);
        }

    });

    }
}

package pl.daniel.cms.client.place.login;

import gwt.material.design.client.ui.MaterialToast;

import java.util.ArrayList;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;

import org.fusesource.restygwt.client.Method;
import org.fusesource.restygwt.client.MethodCallback;

import pl.daniel.cms.client.editor.helper.BeanEditView;
import pl.daniel.cms.client.place.Routing;
import pl.daniel.cms.client.place.app.AppPresenter;
import pl.daniel.cms.client.security.CurrentUser;
import pl.daniel.cms.client.service.LoginService;
import pl.daniel.cms.shared.model.UserLoginModel;

import com.google.gwt.core.shared.GWT;
import com.google.gwt.editor.client.EditorError;
import com.google.gwt.editor.client.SimpleBeanEditorDriver;
import com.google.gwt.event.shared.GwtEvent.Type;
import com.google.gwt.user.client.Window;
import com.google.inject.Inject;
import com.google.web.bindery.event.shared.EventBus;
import com.gwtplatform.mvp.client.HasUiHandlers;
import com.gwtplatform.mvp.client.Presenter;
import com.gwtplatform.mvp.client.annotations.NameToken;
import com.gwtplatform.mvp.client.annotations.ProxyStandard;
import com.gwtplatform.mvp.client.annotations.TabInfo;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.client.proxy.RevealContentHandler;
import com.gwtplatform.mvp.client.proxy.TabContentProxyPlace;

public class LoginPresenter extends Presenter<LoginPresenter.MyView, LoginPresenter.MyProxy> implements LoginUiHandlers {

    @ProxyStandard
    @NameToken(Routing.Url.login)
    @TabInfo(container = AppPresenter.class, label = Routing.Name.login, priority = 2)
    public interface MyProxy extends TabContentProxyPlace<LoginPresenter> {
    }

    public interface MyView extends BeanEditView<UserLoginModel>, HasUiHandlers<LoginUiHandlers> {
    }

    public static final Type<RevealContentHandler<?>> SLOT_Login = new Type<RevealContentHandler<?>>();

    // Editor
    private SimpleBeanEditorDriver<UserLoginModel, ?> editorDriver;
    private static final LoginService service = GWT.create(LoginService.class);
    private UserLoginModel model = new UserLoginModel();

    private final CurrentUser currentUser;
    private final PlaceManager placeManager;
    private final AppPresenter appPresenter;

    @Override
    public void onLoginButtonClick() {
    if (editorDriver.isDirty()) {
        model = editorDriver.flush();
        validateModel();
        if (editorDriver.hasErrors()) {
        MaterialToast.fireToast("Errors occur");
        for (EditorError e : editorDriver.getErrors()) {
            if (e.getAbsolutePath().equals("")) {
            MaterialToast.fireToast(e.getMessage() + " " + e.getPath() + " " + e.getAbsolutePath());
            }
        }
        } else {
        service.login(model.getEmail(), model.getPassword(), new MethodCallback<Void>() {
            @Override
            public void onSuccess(Method method, Void response) {
            MaterialToast.fireToast("Succefully set info. status code: " + response);
            // PlaceRequest request = new
            // PlaceRequest.Builder(placeManager.getCurrentPlaceRequest()).nameToken(Routing.Url.test).build();
            // placeManager.revealPlace(request);
            // placeManager.revealCurrentPlace();
            onToggleLogginButtonClick();
            }

            @Override
            public void onFailure(Method method, Throwable exception) {
            MaterialToast.fireToast(exception.getLocalizedMessage());
            }
        });
        // service.login(model, new MethodCallback<Void>() {
        // @Override
        // public void onSuccess(Method method, Integer response) {
        // MaterialToast.fireToast("Succefully set info. status code: "
        // + response);
        // // PlaceRequest request = new
        // //
        // PlaceRequest.Builder(placeManager.getCurrentPlaceRequest()).nameToken(Routing.Url.test).build();
        // // placeManager.revealPlace(request);
        // placeManager.revealCurrentPlace();
        //
        // }
        //
        // @Override
        // public void onFailure(Method method, Throwable exception) {
        // MaterialToast.fireToast(exception.getLocalizedMessage());
        // }
        // });
        }
    } else {
        MaterialToast.fireToast("Data has not changed");
    }
    }

    private void validateModel() {
    Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    Set<ConstraintViolation<UserLoginModel>> violations = validator.validate(model);
    // model.validate();
    GWT.log(String.valueOf(violations.size()));
    if (violations.size() > 0) {
        editorDriver.setConstraintViolations(new ArrayList<ConstraintViolation<?>>(violations));
    }
    }

    @Inject
    LoginPresenter(EventBus eventBus, MyView view, MyProxy proxy, CurrentUser currentUser, PlaceManager placeManager, AppPresenter appPresenter) {
    super(eventBus, view, proxy, RevealType.Root);
    this.currentUser = currentUser;
    if (!currentUser.isLoggedIn()) {
        placeManager.revealDefaultPlace();
    }
    this.placeManager = placeManager;
    this.appPresenter = appPresenter;
    getView().setUiHandlers(this);
    Window.setTitle(Routing.Name.login);
    editorDriver = getView().createEditorDriver();
    editorDriver.edit(model);

    }

    public enum EditorMode {
    VIEW, EDIT, CREATE
    }

    @Override
    protected void onReveal() {
    GWT.log("reveal");
    if (this.currentUser.isLoggedIn()) {
        MaterialToast.fireToast("User already logged in. Redirecting to home page");
        placeManager.revealDefaultPlace();
    }
    }

    @Override
    protected void onReset() {
    GWT.log("reset");
    }

    @Override
    public void onToggleLogginButtonClick() {
    this.currentUser.switchLoggedIn();
    appPresenter.getView().setLoginButtonVisbility(true);
    // TODO if current place is null redirect do default
    GWT.log("\\\\  " + placeManager.getCurrentPlaceRequest().getNameToken());

    placeManager.revealCurrentPlace();

    };

}

EDIT


Error I got after changing AppModule to:

public class AppModule extends AbstractPresenterModule {
    @Override
    protected void configure() {
    install(new UiModule());

    // Application Presenters
    bindSingletonPresenterWidget(AppPresenter.class, AppPresenter.MyView.class, AppView.class);
    // bindPresenter(AppPresenter.class, AppPresenter.MyView.class, AppView.class, AppPresenter.MyProxy.class);

}
}

[INFO] Scanning for projects...
[INFO] 
[INFO] Using the builder org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder with a thread count of 1
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building cms 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ cms ---
[INFO] Deleting /home/korbeldaniel/git/cms/target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ cms ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 18 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.3:compile (default-compile) @ cms ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 117 source files to /home/korbeldaniel/git/cms/target/cms/WEB-INF/classes
[INFO] /home/korbeldaniel/git/cms/src/main/java/pl/korbeldaniel/cms/server/entity/GenericEntity.java: Some input files use unchecked or unsafe operations.
[INFO] /home/korbeldaniel/git/cms/src/main/java/pl/korbeldaniel/cms/server/entity/GenericEntity.java: Recompile with -Xlint:unchecked for details.
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ cms ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/korbeldaniel/git/cms/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.3:testCompile (default-testCompile) @ cms ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ cms ---
[INFO] No tests to run.
[INFO] 
[INFO] --- gwt-maven-plugin:2.7.0:compile (default) @ cms ---
[INFO] auto discovered modules [pl.korbeldaniel.cms.cms]
[INFO] Compiling module pl.korbeldaniel.cms.cms
[INFO]    Ignored 1 unit with compilation errors in first pass.
[INFO] Compile with -strict or with -logLevel set to TRACE or DEBUG to see all errors.
[INFO]    Computing all possible rebind results for 'pl.korbeldaniel.cms.client.service.LoginService'
[INFO]       Rebinding pl.korbeldaniel.cms.client.service.LoginService
[INFO]          Invoking generator org.fusesource.restygwt.rebind.RestServiceGenerator
[INFO]             Generating: pl.korbeldaniel.cms.client.service.LoginService_Generated_RestServiceProxy_
[INFO]                classname to resolve: org.fusesource.restygwt.rebind.ModelChangeAnnotationResolver
[INFO]                add annotationresolver: org.fusesource.restygwt.rebind.ModelChangeAnnotationResolver
[ERROR] log4j:WARN No appenders could be found for logger (org.hibernate.validator.util.Version).
[ERROR] log4j:WARN Please initialize the log4j system properly.
[ERROR] log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
[INFO]    Compiling 1 permutation
[INFO]       Compiling permutation 0...
[INFO]    Compile of permutations succeeded
[INFO]    Compilation succeeded -- 16,905s
[INFO] Linking into /home/korbeldaniel/git/cms/target/cms/cms
[INFO]    Invoking Linker Verify the availability of a more recent version of GWTP.
[INFO]       Checking version information for gwtp-mvp-client
[INFO]          [WARN] ------------------------------------------------------------
[INFO]          [WARN] A new version of gwtp-mvp-client is available!
[INFO]          [WARN] Your version: 1.5
[INFO]          [WARN] Latest version: 1.5.2
[INFO]          [WARN] See http://search.maven.org/#artifactdetails|com.gwtplatform|gwtp-mvp-client|1.5.2|jar
[INFO]          [WARN] ------------------------------------------------------------
[INFO]    Link succeeded
[INFO]    Linking succeeded -- 0,745s
[INFO] 
[INFO] --- maven-war-plugin:2.6:war (default-war) @ cms ---
[INFO] Packaging webapp
[INFO] Assembling webapp [cms] in [/home/korbeldaniel/git/cms/target/cms]
[INFO] Processing war project
[INFO] Copying webapp resources [/home/korbeldaniel/git/cms/src/main/webapp]
[INFO] Webapp assembled in [111 msecs]
[INFO] Building war: /home/korbeldaniel/git/cms/target/cms.war
[INFO] 
[INFO] --- gwt-maven-plugin:2.7.0:test (default) @ cms ---
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ cms ---
[INFO] Installing /home/korbeldaniel/git/cms/target/cms.war to /home/korbeldaniel/.m2/repository/pl/korbeldaniel/cms/cms/0.0.1-SNAPSHOT/cms-0.0.1-SNAPSHOT.war
[INFO] Installing /home/korbeldaniel/git/cms/pom.xml to /home/korbeldaniel/.m2/repository/pl/korbeldaniel/cms/cms/0.0.1-SNAPSHOT/cms-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 24.520 s
[INFO] Finished at: 2016-03-11T11:09:11+01:00
[INFO] Final Memory: 37M/427M
[INFO] ------------------------------------------------------------------------

Solution

  • You're absolutely correct: Using @Inject in a constructor or on top of field is a way to go. Just please be sure AppPresenter is binded as singleton

    public class ApplicationModule extends AbstractPresenterModule {
            @Override
            protected void configure() {
                bindSingletonPresenterWidget(AppPresenter.class, AppPresenter.MyView.class, AppView.class);
            }
    }
    

    This way each time you @Inject AppPresenter anywhere, you'll end up referencing the exact instance you need, and yes, this is one of benefits of using loosely tied components and dependency injection.