nl.strohalm.cyclos.http.LifecycleListener.java Source code

Java tutorial

Introduction

Here is the source code for nl.strohalm.cyclos.http.LifecycleListener.java

Source

/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
    
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
    
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
 */
package nl.strohalm.cyclos.http;

import java.util.Collection;
import java.util.concurrent.Callable;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import nl.strohalm.cyclos.annotations.Inject;
import nl.strohalm.cyclos.entities.settings.LocalSettings;
import nl.strohalm.cyclos.initializations.LocalWebInitialization;
import nl.strohalm.cyclos.services.access.AccessService;
import nl.strohalm.cyclos.services.access.exceptions.NotConnectedException;
import nl.strohalm.cyclos.services.application.ApplicationService;
import nl.strohalm.cyclos.services.settings.SettingsService;
import nl.strohalm.cyclos.utils.SpringHelper;
import nl.strohalm.cyclos.utils.TransactionHelper;
import nl.strohalm.cyclos.utils.access.LoggedUser;
import nl.strohalm.cyclos.utils.transaction.CurrentTransactionData;
import nl.strohalm.cyclos.utils.transaction.TransactionEndListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * Listener for context events
 * @author luis
 */
public class LifecycleListener implements ServletContextListener, HttpSessionListener {

    private static final Log LOG = LogFactory.getLog(LifecycleListener.class);

    private AccessService accessService;
    private TransactionHelper transactionHelper;
    private SettingsService settingsService;
    private ApplicationService applicationService;

    /**
     * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
     */
    @Override
    public void contextDestroyed(final ServletContextEvent event) {
        LoggedUser.runAsSystem(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                try {
                    final ServletContext context = event.getServletContext();
                    final LocalSettings settings = settingsService == null ? null
                            : settingsService.getLocalSettings();

                    // Shutdown the application service
                    if (applicationService != null) {
                        applicationService.shutdown();
                    }

                    final String applicationName = settings == null ? null : settings.getApplicationName();
                    context.log(applicationName == null ? "Cyclos" : applicationName + " destroyed");

                    // Suggest a GC as probably there were several released resources
                    System.gc();

                } catch (final Throwable e) {
                    LOG.error("Error on LifecycleListener.contextDestroyed()", e);
                    throw new RuntimeException(e);
                }
                return null; // required by compiler
            }
        });
    }

    /**
     * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
     */
    @Override
    public void contextInitialized(final ServletContextEvent event) {
        LoggedUser.runAsSystem(new Callable<Void>() {
            @Override
            public Void call() {
                try {
                    final ServletContext context = event.getServletContext();

                    final WebApplicationContext applicationContext = WebApplicationContextUtils
                            .getWebApplicationContext(context);
                    SpringHelper.injectBeans(applicationContext, LifecycleListener.this);

                    applicationService.initialize();

                    context.setAttribute("systemOnline", applicationService.isOnline());
                    context.setAttribute("cyclosVersion", applicationService.getCyclosVersion());

                    // Run web initializations
                    final Collection<LocalWebInitialization> initializations = applicationContext
                            .getBeansOfType(LocalWebInitialization.class).values();
                    runAll(initializations);

                    final LocalSettings settings = settingsService.getLocalSettings();
                    context.log(settings.getApplicationName() + " initialized");

                    // Suggest a GC in order to keep the heap low right after a startup
                    System.gc();
                } catch (final Throwable e) {
                    LOG.error("Error on LifecycleListener.contextInitialized()", e);
                    throw new RuntimeException(e);
                }
                return null; // required by compiler
            }
        });
    }

    /**
     * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent)
     */
    @Override
    public void sessionCreated(final HttpSessionEvent event) {
        // Nothing to do
    }

    /**
     * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
     */
    @Override
    public void sessionDestroyed(final HttpSessionEvent event) {
        final HttpSession session = event.getSession();
        final String sessionId = session == null ? null : session.getId();
        if (sessionId == null) {
            return;
        }

        // If there is an active transaction, use an transaction end listener to actually logout
        if (transactionHelper.hasActiveTransaction()) {
            CurrentTransactionData.addTransactionEndListener(new TransactionEndListener() {
                @Override
                protected void onTransactionEnd(final boolean commit) {
                    doLogout(sessionId);
                }
            });
        } else {
            // Logout directly (this is in another TX)
            doLogout(sessionId);
        }
    }

    @Inject
    public void setAccessService(final AccessService accessService) {
        this.accessService = accessService;
    }

    @Inject
    public void setApplicationService(final ApplicationService applicationService) {
        this.applicationService = applicationService;
    }

    @Inject
    public void setSettingsService(final SettingsService settingsService) {
        this.settingsService = settingsService;
    }

    @Inject
    public void setTransactionHelper(final TransactionHelper transactionHelper) {
        this.transactionHelper = transactionHelper;
    }

    private void doLogout(final String sessionId) {
        transactionHelper.runInNewTransaction(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(final TransactionStatus status) {
                try {
                    accessService.logout(sessionId);
                } catch (final NotConnectedException e) {
                    // Ok, just ignore
                } catch (final RuntimeException e) {
                    LOG.warn("Error logging out member on session destroy", e);
                    status.setRollbackOnly();
                }
            }
        });
    }

    /**
     * Run a single initialization inside a transaction if it is required
     */
    private void run(final LocalWebInitialization initialization) {
        LOG.debug(String.format("Running web initialization (%s)...", initialization.getName()));
        transactionHelper.runInCurrentThread(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(final TransactionStatus status) {
                try {
                    initialization.initialize();
                } catch (final RuntimeException e) {
                    LOG.error(String.format("Error running web initialization: %s", initialization.getName()), e);
                    throw e;
                }
            }
        });
    }

    /**
     * Run all given initializations / finalizations
     */
    private void runAll(final Collection<LocalWebInitialization> initializations) {
        try {
            for (final LocalWebInitialization initialization : initializations) {
                run(initialization);
            }
        } finally {
            CurrentTransactionData.cleanup();
        }
    }
}