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

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.web.DefaultApp.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.google.common.base.Strings;
import com.haulmont.cuba.security.global.LoginException;
import com.haulmont.cuba.security.global.UserSession;
import com.haulmont.cuba.web.app.loginwindow.AppLoginWindow;
import com.haulmont.cuba.web.security.AnonymousUserCredentials;
import com.haulmont.cuba.web.security.events.AppLoggedInEvent;
import com.haulmont.cuba.web.security.events.AppLoggedOutEvent;
import com.haulmont.cuba.web.security.events.AppStartedEvent;
import com.haulmont.cuba.web.sys.VaadinSessionScope;
import com.vaadin.server.*;
import com.vaadin.ui.UI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Locale;

import static com.haulmont.cuba.web.Connection.*;
import static com.haulmont.cuba.web.security.ExternalUserCredentials.isLoggedInWithExternalAuth;

/**
 * Default {@link App} implementation that shows {@link AppLoginWindow} on start. Single instance of App is bound to
 * single HTTP session.
 */
@Component(App.NAME)
@Scope(VaadinSessionScope.NAME)
public class DefaultApp extends App implements StateChangeListener, UserSubstitutionListener {

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

    public DefaultApp() {
    }

    @Override
    protected Connection createConnection() {
        Connection connection = super.createConnection();
        connection.addStateChangeListener(this);
        return connection;
    }

    @Override
    public void connectionStateChanged(StateChangeEvent event) {
        Connection connection = event.getSource();

        log.debug("connectionStateChanged connected: {}, authenticated: {}", connection.isConnected(),
                connection.isAuthenticated());

        cleanupBackgroundTasks();
        closeAllWindows();
        clearSettingsCache();

        if (connection.isConnected()) {
            UserSession userSession = connection.getSessionNN();
            setLocale(userSession.getLocale());

            // substitution listeners are cleared by connection on logout
            connection.addUserSubstitutionListener(this);

            preventSessionFixation(connection, userSession);

            initExceptionHandlers(true);

            initializeUi();

            if (linkHandler != null && linkHandler.canHandleLink()) {
                linkHandler.handle();
                linkHandler = null;
            }

            afterLoggedIn();

            publishAppLoggedInEvent();
        } else {
            initExceptionHandlers(false);

            VaadinRequest currentRequest = VaadinService.getCurrentRequest();
            if (currentRequest != null) {
                Locale requestLocale = currentRequest.getLocale();
                setLocale(resolveLocale(requestLocale));
            }

            try {
                connection.login(new AnonymousUserCredentials(getLocale()));
            } catch (LoginException e) {
                throw new RuntimeException("Unable to login as anonymous!");
            }

            publishAppLoggedOutEvent(event.getPreviousSession());
        }
    }

    protected void publishAppLoggedOutEvent(UserSession previousSession) {
        AppLoggedOutEvent event = new AppLoggedOutEvent(this, previousSession);
        events.publish(event);

        String loggedOutUrl = event.getRedirectUrl();
        if (loggedOutUrl != null) {
            redirectAfterLogout(loggedOutUrl);
        }
    }

    protected void redirectAfterLogout(String loggedOutUrl) {
        if (!Strings.isNullOrEmpty(loggedOutUrl)) {
            AppUI currentUi = AppUI.getCurrent();
            // it can be null if we handle request in a custom RequestHandler
            if (currentUi != null) {
                currentUi.setContent(null);
                currentUi.getPage().setLocation(loggedOutUrl);
            } else {
                VaadinResponse response = VaadinService.getCurrentResponse();
                try {
                    ((VaadinServletResponse) response).getHttpServletResponse().sendRedirect(loggedOutUrl);
                } catch (IOException e) {
                    log.error("Error on send redirect to client", e);
                }
            }

            VaadinSession vaadinSession = VaadinSession.getCurrent();
            for (UI ui : vaadinSession.getUIs()) {
                if (ui != currentUi) {
                    ui.access(() -> {
                        ui.setContent(null);
                        ui.getPage().setLocation(loggedOutUrl);
                    });
                }
            }
        }
    }

    protected void publishAppLoggedInEvent() {
        AppLoggedInEvent event = new AppLoggedInEvent(this);
        events.publish(event);
    }

    protected void initializeUi() {
        AppUI currentUi = AppUI.getCurrent();
        if (currentUi != null) {
            createTopLevelWindow(currentUi);
        }

        for (AppUI ui : getAppUIs()) {
            if (currentUi != ui) {
                ui.accessSynchronously(() -> createTopLevelWindow(ui));
            }
        }
    }

    protected void preventSessionFixation(Connection connection, UserSession userSession) {
        if (connection.isAuthenticated() && !isLoggedInWithExternalAuth(userSession)
                && webConfig.getUseSessionFixationProtection() && VaadinService.getCurrentRequest() != null) {

            VaadinService.reinitializeSession(VaadinService.getCurrentRequest());

            WrappedSession session = VaadinSession.getCurrent().getSession();
            int timeout = webConfig.getHttpSessionExpirationTimeoutSec();
            session.setMaxInactiveInterval(timeout);

            HttpSession httpSession = session instanceof WrappedHttpSession
                    ? ((WrappedHttpSession) session).getHttpSession()
                    : null;
            log.debug("Session reinitialized: HttpSession={}, timeout={}sec, UserSession={}", httpSession, timeout,
                    connection.getSession());
        }
    }

    @Override
    protected String routeTopLevelWindowId() {
        if (connection.isAuthenticated()) {
            return "mainWindow";
        } else {
            return "loginWindow";
        }
    }

    /**
     * Perform actions after successful login. Will be removed in 7.0.
     *
     * @deprecated Use {@link AppLoggedInEvent} instead.
     */
    @Deprecated
    protected void afterLoggedIn() {
    }

    @Override
    public void loginOnStart() throws LoginException {
        publishAppStartedEvent();

        if (!connection.isConnected()) {
            try {
                connection.login(new AnonymousUserCredentials(getLocale()));
            } catch (LoginException e) {
                throw new RuntimeException("Unable to login as anonymous!");
            }
        }
    }

    protected void publishAppStartedEvent() throws LoginException {
        try {
            events.publish(new AppStartedEvent(this));
        } catch (UndeclaredThrowableException ex) {
            Throwable cause = ex.getCause();
            if (cause instanceof LoginException) {
                throw (LoginException) cause;
            } else {
                throw ex;
            }
        }
    }

    @Override
    public void navigateTo(String topLevelWindowId) {
        cleanupBackgroundTasks();
        clearSettingsCache();
        closeAllWindows();

        super.navigateTo(topLevelWindowId);
    }

    @Override
    public void userSubstituted(UserSubstitutedEvent event) {
        cleanupBackgroundTasks();
        clearSettingsCache();
        closeAllWindows();

        initializeUi();
    }
}