com.haulmont.cuba.web.AppUI.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.web.AppUI.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.haulmont.cuba.web;

import com.haulmont.cuba.client.ClientUserSession;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.gui.TestIdManager;
import com.haulmont.cuba.gui.components.Window.TopLevelWindow;
import com.haulmont.cuba.gui.events.sys.UiEventsMulticaster;
import com.haulmont.cuba.gui.theme.ThemeConstantsRepository;
import com.haulmont.cuba.gui.xml.layout.ExternalUIComponentsSource;
import com.haulmont.cuba.security.app.UserSessionService;
import com.haulmont.cuba.security.global.LoginException;
import com.haulmont.cuba.security.global.UserSession;
import com.haulmont.cuba.web.app.UserSettingsTools;
import com.haulmont.cuba.web.controllers.ControllerUtils;
import com.haulmont.cuba.web.events.UIRefreshEvent;
import com.haulmont.cuba.web.security.events.AppInitializedEvent;
import com.haulmont.cuba.web.security.events.SessionHeartbeatEvent;
import com.haulmont.cuba.web.sys.LinkHandler;
import com.haulmont.cuba.web.toolkit.ui.*;
import com.haulmont.cuba.web.toolkit.ui.client.appui.AppUIClientRpc;
import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.annotations.Push;
import com.vaadin.server.ErrorHandler;
import com.vaadin.server.Extension;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.WrappedSession;
import com.vaadin.shared.ui.ui.Transport;
import com.vaadin.ui.*;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;

import javax.inject.Inject;
import java.util.*;

/**
 * Single window / page of web application. Root component of Vaadin layout.
 */
@org.springframework.stereotype.Component(AppUI.NAME)
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Push(transport = Transport.WEBSOCKET_XHR)
@PreserveOnRefresh
public class AppUI extends UI implements ErrorHandler, CubaHistoryControl.HistoryBackHandler {

    public static final String NAME = "cuba_AppUI";

    public static final String LAST_REQUEST_ACTION_ATTR = "lastRequestAction";
    public static final String LAST_REQUEST_PARAMS_ATTR = "lastRequestParams";

    private static final Logger log = LoggerFactory.getLogger(AppUI.class);

    protected App app;

    @Inject
    protected Messages messages;

    @Inject
    protected Events events;

    @Inject
    protected GlobalConfig globalConfig;

    @Inject
    protected WebConfig webConfig;

    @Inject
    protected ScreenProfilerConfig screenProfilerConfig;

    @Inject
    protected UserSettingsTools userSettingsTools;

    @Inject
    protected ThemeConstantsRepository themeConstantsRepository;

    @Inject
    protected ExternalUIComponentsSource externalUIComponentsSource;

    @Inject
    protected UserSessionSource userSessionSource;

    @Inject
    protected UserSessionService userSessionService;

    @Inject
    protected UiEventsMulticaster uiEventsMulticaster;

    protected TestIdManager testIdManager = new TestIdManager();

    protected boolean testMode = false;

    protected String profilerMarker;

    protected Map<String, String> profiledScreens;

    protected CubaClientManager clientManager;

    protected ScreenClientProfilerAgent clientProfiler;

    protected CubaFileDownloader fileDownloader;

    protected CubaHistoryControl historyControl;

    protected TopLevelWindow topLevelWindow;

    public AppUI() {
    }

    /**
     * Dynamically init external JS libraries.
     * You should create JavaScriptExtension class and extend UI object here. <br>
     * <p>
     * Example: <br>
     * <pre><code>
     * JavaScriptExtension:
     *
     * {@literal @}JavaScript("resources/jquery/jquery-1.10.2.min.js")
     * public class JQueryIntegration extends AbstractJavaScriptExtension {
     *
     *     {@literal @}Override
     *     public void extend(AbstractClientConnector target) {
     *         super.extend(target);
     *     }
     *
     *     {@literal @}Override
     *     protected Class&lt;? extends ClientConnector&gt; getSupportedParentType() {
     *         return UI.class;
     *     }
     * }
     *
     * AppUI:
     *
     * protected void initJsLibraries() {
     *     new JQueryIntegration().extend(this);
     * }</code></pre>
     * <p>
     * If you want to include scripts to generated page statically see {@link com.haulmont.cuba.web.sys.CubaBootstrapListener}.
     */
    protected void initJsLibraries() {
    }

    protected void initInternalComponents() {
        clientManager = new CubaClientManager();
        clientManager.extend(this);

        fileDownloader = new CubaFileDownloader();
        fileDownloader.extend(this);

        clientProfiler = new ScreenClientProfilerAgent();
        clientProfiler.extend(this);

        if (webConfig.getAllowHandleBrowserHistoryBack()) {
            historyControl = new CubaHistoryControl();
            historyControl.extend(this, this);
        }
    }

    protected App createApplication() {
        return AppBeans.getPrototype(App.NAME);
    }

    @Override
    protected void init(VaadinRequest request) {
        log.trace("Initializing UI {}", this);

        try {
            this.testMode = globalConfig.getTestMode();

            // init error handlers
            setErrorHandler(this);

            // do not grab focus
            setTabIndex(-1);

            initJsLibraries();

            initInternalComponents();

            externalUIComponentsSource.checkInitialized();

            if (!App.isBound()) {
                App app = createApplication();
                app.init(request.getLocale());

                this.app = app;

                publishAppInitializedEvent(app);
            } else {
                this.app = App.getInstance();
            }

            setupUI();
        } catch (Exception e) {
            log.error("Unable to init ui", e);

            // unable to connect to middle ware
            showCriticalExceptionMessage(e);
            return;
        }

        processExternalLink(request);
    }

    protected void publishAppInitializedEvent(App app) {
        events.publish(new AppInitializedEvent(app));
    }

    protected void showCriticalExceptionMessage(Exception exception) {
        String initErrorCaption = messages.getMainMessage("app.initErrorCaption");
        String initErrorMessage = messages.getMainMessage("app.initErrorMessage");

        VerticalLayout content = new VerticalLayout();
        content.setStyleName("c-init-error-view");
        content.setSizeFull();

        VerticalLayout errorPanel = new VerticalLayout();
        errorPanel.setStyleName("c-init-error-panel");
        errorPanel.setWidthUndefined();
        errorPanel.setSpacing(true);

        Label captionLabel = new Label(initErrorCaption);
        captionLabel.setWidthUndefined();
        captionLabel.setStyleName("c-init-error-caption");
        captionLabel.addStyleName("h2");
        captionLabel.setValue(initErrorCaption);

        errorPanel.addComponent(captionLabel);

        Label messageLabel = new Label(initErrorCaption);
        messageLabel.setWidthUndefined();
        messageLabel.setStyleName("c-init-error-message");
        messageLabel.setValue(initErrorMessage);

        errorPanel.addComponent(messageLabel);

        Button retryButton = new Button(messages.getMainMessage("app.initRetry"));
        retryButton.setStyleName("c-init-error-retry");
        retryButton.addClickListener(event -> {
            // always restart UI
            String url = ControllerUtils.getLocationWithoutParams() + "?restartApp";
            getPage().open(url, "_self");
        });

        errorPanel.addComponent(retryButton);
        errorPanel.setComponentAlignment(retryButton, Alignment.MIDDLE_CENTER);

        content.addComponent(errorPanel);
        content.setComponentAlignment(errorPanel, Alignment.MIDDLE_CENTER);

        setContent(content);
    }

    protected void setupUI() throws LoginException {
        if (!app.getConnection().isConnected()) {
            app.loginOnStart();
        } else {
            app.createTopLevelWindow(this);
        }
    }

    @Override
    protected void refresh(VaadinRequest request) {
        super.refresh(request);

        boolean sessionIsAlive = true;

        Connection connection = app.getConnection();

        if (connection.isAuthenticated()) {
            // Ping middleware session if connected
            log.debug("Ping middleware session");

            try {
                UserSession session = connection.getSession();
                if (session instanceof ClientUserSession && ((ClientUserSession) session).isAuthenticated()) {
                    userSessionService.getUserSession(session.getId());

                }
            } catch (Exception e) {
                sessionIsAlive = false;

                app.exceptionHandlers.handle(new com.vaadin.server.ErrorEvent(e));
            }

            if (sessionIsAlive) {
                events.publish(new SessionHeartbeatEvent(app));
            }
        }

        if (sessionIsAlive) {
            events.publish(new UIRefreshEvent(this));
        }
    }

    @Override
    public void handleRequest(VaadinRequest request) {
        // on refresh page call
        processExternalLink(request);
    }

    /**
     * @return current AppUI
     */
    public static AppUI getCurrent() {
        return (AppUI) UI.getCurrent();
    }

    /**
     * @return this App instance
     */
    public App getApp() {
        return app;
    }

    /**
     * @return currently displayed top-level window
     */
    public TopLevelWindow getTopLevelWindow() {
        return topLevelWindow;
    }

    /**
     * INTERNAL.
     * Set currently displayed top-level window.
     */
    public void setTopLevelWindow(TopLevelWindow window) {
        if (this.topLevelWindow != window) {
            this.topLevelWindow = window;

            // unregister previous components
            setContent(null);

            setContent(topLevelWindow.unwrapComposition(Component.class));
        }
    }

    public TestIdManager getTestIdManager() {
        return testIdManager;
    }

    public boolean isTestMode() {
        return testMode;
    }

    @Override
    public void error(com.vaadin.server.ErrorEvent event) {
        try {
            app.getExceptionHandlers().handle(event);
            app.getAppLog().log(event);
        } catch (Throwable e) {
            //noinspection ThrowableResultOfMethodCallIgnored
            log.error("Error handling exception\nOriginal exception:\n{}\nException in handlers:\n{}",
                    ExceptionUtils.getStackTrace(event.getThrowable()), ExceptionUtils.getStackTrace(e));
        }
    }

    public void processExternalLink(VaadinRequest request) {
        WrappedSession wrappedSession = request.getWrappedSession();

        String action = (String) wrappedSession.getAttribute(LAST_REQUEST_ACTION_ATTR);

        if (webConfig.getLinkHandlerActions().contains(action)) {
            //noinspection unchecked
            Map<String, String> params = (Map<String, String>) wrappedSession
                    .getAttribute(LAST_REQUEST_PARAMS_ATTR);
            params = params != null ? params : Collections.emptyMap();

            try {
                LinkHandler linkHandler = AppBeans.getPrototype(LinkHandler.NAME, app, action, params);
                if (app.connection.isConnected() && linkHandler.canHandleLink()) {
                    linkHandler.handle();
                } else {
                    app.linkHandler = linkHandler;
                }
            } catch (Exception e) {
                error(new com.vaadin.server.ErrorEvent(e));
            }
        }
    }

    @Override
    public void detach() {
        log.trace("Detaching UI {}", this);
        super.detach();
    }

    /**
     * INTERNAL.
     */
    public void discardAccumulatedEvents() {
        getRpcProxy(AppUIClientRpc.class).discardAccumulatedEvents();
    }

    public String getProfilerMarker() {
        return profilerMarker;
    }

    public void setProfilerMarker(String profilerMarker) {
        this.profilerMarker = profilerMarker;
    }

    public void setProfiledScreen(String profilerMarker, String screen) {
        if (profiledScreens == null) {
            profiledScreens = new HashMap<>();
        }
        profiledScreens.put(profilerMarker, screen);
    }

    public String getProfiledScreen(String profilerMarker) {
        return profiledScreens.get(profilerMarker);
    }

    public void clearProfiledScreens(List<String> profilerMarkers) {
        if (profiledScreens != null) {
            for (String profilerMarker : profilerMarkers) {
                profiledScreens.remove(profilerMarker);
            }
        }
    }

    protected void updateClientSystemMessages(Locale locale) {
        CubaClientManager.SystemMessages msgs = new CubaClientManager.SystemMessages();

        msgs.communicationErrorCaption = messages.getMainMessage("communicationErrorCaption", locale);
        msgs.communicationErrorMessage = messages.getMainMessage("communicationErrorMessage", locale);

        msgs.sessionExpiredErrorCaption = messages.getMainMessage("sessionExpiredErrorCaption", locale);
        msgs.sessionExpiredErrorMessage = messages.getMainMessage("sessionExpiredErrorMessage", locale);

        msgs.authorizationErrorCaption = messages.getMainMessage("authorizationErrorCaption", locale);
        msgs.authorizationErrorMessage = messages.getMainMessage("authorizationErrorMessage", locale);

        clientManager.updateSystemMessagesLocale(msgs);

        getReconnectDialogConfiguration().setDialogText(messages.getMainMessage("reconnectDialogText", locale));
        getReconnectDialogConfiguration()
                .setDialogTextGaveUp(messages.getMainMessage("reconnectDialogTextGaveUp", locale));
    }

    @Override
    public void onHistoryBackPerformed() {
        TopLevelWindow topLevelWindow = getTopLevelWindow();
        if (topLevelWindow instanceof CubaHistoryControl.HistoryBackHandler) {
            ((CubaHistoryControl.HistoryBackHandler) topLevelWindow).onHistoryBackPerformed();
        }
    }

    protected AbstractComponent getTopLevelWindowComposition() {
        if (topLevelWindow == null) {
            throw new IllegalStateException("UI does not have top level window");
        }

        return topLevelWindow.unwrapComposition(AbstractComponent.class);
    }

    public List<CubaTimer> getTimers() {
        AbstractComponent timersHolder = getTopLevelWindowComposition();

        List<CubaTimer> timers = new ArrayList<>();
        for (Extension extension : timersHolder.getExtensions()) {
            if (extension instanceof CubaTimer) {
                timers.add((CubaTimer) extension);
            }
        }
        return timers;
    }

    public void addTimer(CubaTimer timer) {
        AbstractComponent timersHolder = getTopLevelWindowComposition();

        if (!timersHolder.getExtensions().contains(timer)) {
            timer.extend(timersHolder);
        }
    }

    public void removeTimer(CubaTimer timer) {
        AbstractComponent timersHolder = getTopLevelWindowComposition();

        timersHolder.removeExtension(timer);
    }

    public void beforeTopLevelWindowInit() {
        updateUiTheme();

        setProfilerParameters();

        updateClientSystemMessages(app.getLocale());

        getTestIdManager().reset();
    }

    protected void setProfilerParameters() {
        clientProfiler.setFlushEventsCount(screenProfilerConfig.getFlushEventsCount());
        clientProfiler.setFlushTimeout(screenProfilerConfig.getFlushTimeout());
    }

    protected void updateUiTheme() {
        UserSession userSession = userSessionSource.getUserSession();

        if (userSession instanceof ClientUserSession && ((ClientUserSession) userSession).isAuthenticated()) {
            // load theme from user settings
            String themeName = userSettingsTools.loadAppWindowTheme();

            if (!Objects.equals(themeName, getTheme())) {
                // check theme support
                Set<String> supportedThemes = themeConstantsRepository.getAvailableThemes();
                if (supportedThemes.contains(themeName)) {
                    app.applyTheme(themeName);
                    setTheme(themeName);
                }
            }
        }
    }

    public CubaFileDownloader getFileDownloader() {
        return fileDownloader;
    }

    public UiEventsMulticaster getUiEventsMulticaster() {
        return uiEventsMulticaster;
    }
}