package org.ovirt.engine.ui.common.system; import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.businessentities.aaa.DbUser; import org.ovirt.engine.ui.common.DisplayUncaughtUIExceptions; import org.ovirt.engine.ui.common.auth.AutoLoginData; import org.ovirt.engine.ui.common.auth.CurrentUser; import org.ovirt.engine.ui.common.auth.CurrentUser.LogoutHandler; import org.ovirt.engine.ui.common.logging.ApplicationLogManager; import org.ovirt.engine.ui.common.uicommon.FrontendEventsHandlerImpl; import org.ovirt.engine.ui.common.uicommon.FrontendFailureEventListener; import org.ovirt.engine.ui.common.widget.AlertManager; import org.ovirt.engine.ui.frontend.AsyncQuery; import org.ovirt.engine.ui.frontend.Frontend; import org.ovirt.engine.ui.uicommonweb.ITypeResolver; import org.ovirt.engine.ui.uicommonweb.TypeResolver; import org.ovirt.engine.ui.uicommonweb.auth.CurrentUserRole; import org.ovirt.engine.ui.uicommonweb.models.LoginModel; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.event.shared.EventBus; import com.google.gwt.user.client.Window; import com.google.inject.Provider; import com.gwtplatform.mvp.client.Bootstrapper; /** * Contains initialization logic that gets executed at application startup. * * @param <T> * Login model type. */ public abstract class BaseApplicationInit<T extends LoginModel> implements Bootstrapper, LogoutHandler { private final ITypeResolver typeResolver; private final FrontendEventsHandlerImpl frontendEventsHandler; protected final FrontendFailureEventListener frontendFailureEventListener; protected final CurrentUser user; protected final EventBus eventBus; protected final Frontend frontend; private final CurrentUserRole currentUserRole; // Using Provider because any UiCommon model will fail before TypeResolver is initialized private final Provider<T> loginModelProvider; private final LockInteractionManager lockInteractionManager; private final ApplicationLogManager applicationLogManager; private final AlertManager alertManager; public BaseApplicationInit(ITypeResolver typeResolver, FrontendEventsHandlerImpl frontendEventsHandler, FrontendFailureEventListener frontendFailureEventListener, CurrentUser user, EventBus eventBus, Provider<T> loginModelProvider, LockInteractionManager lockInteractionManager, Frontend frontend, CurrentUserRole currentUserRole, ApplicationLogManager applicationLogManager, AlertManager alertManager) { this.typeResolver = typeResolver; this.frontendEventsHandler = frontendEventsHandler; this.frontendFailureEventListener = frontendFailureEventListener; this.user = user; this.eventBus = eventBus; this.loginModelProvider = loginModelProvider; this.lockInteractionManager = lockInteractionManager; this.frontend = frontend; this.currentUserRole = currentUserRole; this.applicationLogManager = applicationLogManager; this.alertManager = alertManager; } @Override public final void onBootstrap() { initUncaughtExceptionHandler(); // Perform actual bootstrap via deferred command to ensure that // UncaughtExceptionHandler is effective during the bootstrap Scheduler.get().scheduleDeferred(() -> performBootstrap()); } void initUncaughtExceptionHandler() { // Prevent uncaught exceptions from escaping application code GWT.setUncaughtExceptionHandler(t -> { applicationLogManager.logUncaughtException(t); if (DisplayUncaughtUIExceptions.getValue()) { alertManager.showUncaughtExceptionAlert(t); } }); } /** * Actual initialization logic that bootstraps the application. */ protected void performBootstrap() { // Handle UI logout requests user.setLogoutHandler(this); // Initialize UiCommon infrastructure initUiCommon(); initFrontend(); initLoginModel(); // Check if the user should be logged in automatically AutoLoginData userInfo = AutoLoginData.instance(); if (userInfo != null) { handleUserInfo(userInfo); user.setAutoLogin(true); } } protected T getLoginModel() { return loginModelProvider.get(); } protected void initLoginModel() { final T loginModel = getLoginModel(); // Add model login event handler loginModel.getLoggedInEvent().addListener((ev, sender, args) -> onLogin(loginModel)); loginModel.getCreateInstanceOnly().getEntityChangedEvent().addListener((ev, sender, args) -> currentUserRole.setCreateInstanceOnly(loginModel.getCreateInstanceOnly().getEntity() )); } /** * Called right after the model fires its login event. */ protected abstract void onLogin(T loginModel); @Override public void onLogout() { AsyncQuery<VdcReturnValueBase> query = new AsyncQuery<>(returnValue -> { // Redirect to SSO Logout after the user has logged out successfully on backend. Window.Location.assign(GWT.getModuleBaseURL() + "sso/logout"); //$NON-NLS-1$ }); query.setHandleFailure(true); frontend.logoffAsync(query); } @Override public void onSessionExpired() { Window.Location.reload(); } protected void performLogin(T loginModel) { DbUser loggedUser = loginModel.getLoggedUser(); beforeLogin(); // UiCommon login preparation frontend.initLoggedInUser(loggedUser); // UI login actions user.login(); afterLogin(); // Perform initial GWTP place transition performPlaceTransition(); } protected void performPlaceTransition() { user.fireLoginChangeEvent(); } protected void beforeLogin() { } protected void afterLogin() { } protected void initUiCommon() { // Set up UiCommon type resolver TypeResolver.initialize(typeResolver); } protected void initFrontend() { // Set up Frontend event handlers frontend.setEventsHandler(frontendEventsHandler); frontend.getFrontendFailureEvent().addListener(frontendFailureEventListener); frontend.getFrontendNotLoggedInEvent().addListener((ev, sender, args) -> user.sessionExpired()); frontend.setFilterQueries(filterFrontendQueries()); } /** * Indicates if all queries triggered through {@link Frontend} should be filtered or not. * <p> * A query that is filtered has its results constrained by user permissions. On the other hand, a query that is not * filtered returns all matching results without additional constraints. */ protected abstract boolean filterFrontendQueries(); /** * When a user is already logged in on the server, the server provides user data within the host page. */ protected void handleUserInfo(AutoLoginData userInfo) { final DbUser loggedUser = userInfo.getDbUser(); // Use deferred command because CommonModel change needs to happen // after all model providers have been properly initialized Scheduler.get().scheduleDeferred(() -> { lockInteractionManager.showLoadingIndicator(); getLoginModel().autoLogin(loggedUser); }); user.setUserInfo(userInfo); } }