ГВО. Как получить доступ от одного ведущего к другому - они не связаны механизмом слотов

У меня есть один ведущий для экрана входа в систему. И у меня есть AppPresenter для всего приложения. Каждое представление (кроме входа в систему) отображается внутри слотов AppView.

В AppView у меня есть кнопка выхода из системы, которая должна быть видна только тогда, когда пользователь вошел в систему, поэтому, когда пользователь входит в систему, кнопка становится видимой. Когда пользователь нажмет на нее, чтобы выйти из системы, кнопка должна исчезнуть.

Скрыть это просто, потому что это происходит в одном представлении/презентаторе. Но у меня есть проблема с отображением этой кнопки после входа пользователя в систему, потому что это происходит на другом ведущем/представлении.

Я новичок в gwtp, поэтому, пожалуйста, помогите мне решить эту проблему.

Как мне получить доступ к другому докладчику из первого входа? Они не родственники! Будет ли достаточно и хорошо, если я просто добавлю класс AppPresenter в конструктор LoginPresenter с аннотацией @Inject? Следующим образом:

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

    }
}

Ведущие:

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

    };

}

РЕДАКТИРОВАТЬ


Ошибка, которую я получил после изменения AppModule на:

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] ------------------------------------------------------------------------

person masterdany88    schedule 03.03.2016    source источник


Ответы (1)


Вы абсолютно правы: использование @Inject в конструкторе или поверх поля — это путь. Просто убедитесь, что AppPresenter привязан как синглтон

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

Таким образом, каждый раз, когда вы используете @Inject AppPresenter в любом месте, вы в конечном итоге будете ссылаться на именно тот экземпляр, который вам нужен, и да, это одно из преимуществ использования слабо связанных компонентов и внедрения зависимостей.

person Роман Гуйван    schedule 03.03.2016
comment
После этого я получаю пустую белую страницу без ошибок. - person masterdany88; 04.03.2016
comment
ваши инъекции GIN могут вызвать это, я думаю, попробуйте перестроить его с помощью maven, чтобы увидеть ошибку (в superdev вы ее не получите) во время предварительной компиляции. Убедитесь, что у вас нет циклических зависимостей и все ваши привязки верны. - person Роман Гуйван; 04.03.2016
comment
да. у вас есть перекрестные ссылки? как AppPresenter, введенный в логин, и логин, введенный в AppPresenter? - person Роман Гуйван; 04.03.2016
comment
Нет. Проверьте мой пост. Я обновил код докладчика. - person masterdany88; 04.03.2016
comment
bindPresenter(AppPresenter.class, AppPresenter.MyView.class, AppView.class, AppPresenter.MyProxy.class); - неправильно. Таким образом, внедрив его в конструктор LoginPresenter, вы каждый раз будете получать НОВЫЙ экземпляр, а не тот, который вы ожидали получить. Измените его на bindSingletonPresenterWidget. - person Роман Гуйван; 04.03.2016
comment
Привязка SingletonPresenterWidget вызывает ошибку. Я получаю пустой экран. Когда я только привязываю PresenterWidget, все в порядке. - person masterdany88; 09.03.2016
comment
AppPresenter — это Presenter, а не PresenterWidget. Я только что проверил документацию - javadoc.gwt-platform.googlecode.com/hg/0.5/com/gwtplatform/mvp/ все подклассы Presenter в любом случае являются синглтонами, поэтому даже bindPresenter будет работать. Если вы можете проверить свой проект на GitHub, я думаю, что смогу помочь вам решить проблему, с точки зрения вопросов - ответ правильный, и на самом деле добавить нечего. - person Роман Гуйван; 11.03.2016