edu.cornell.mannlib.vitro.webapp.startup.StartupManager.java Source code

Java tutorial

Introduction

Here is the source code for edu.cornell.mannlib.vitro.webapp.startup.StartupManager.java

Source

/* $This file is distributed under the terms of the license in /doc/license.txt$ */

package edu.cornell.mannlib.vitro.webapp.startup;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Instantiate and run the ServletContextListeners for Vitro, while accumulating
 * messages in StartupStatus.
 * 
 * The startup listeners are stored in a file with one full-qualified class name
 * per line. Blank lines and comment lines (starting with '#') are ignored.
 * 
 * No exception in the listeners should prevent the successful completion.
 * However, an uncaught exception or a fatal error status will cause the
 * StartupStatusDisplayFilter to disply the problem instead of showing the home
 * page (or any other requested page).
 */
public class StartupManager implements ServletContextListener {
    private static final Log log = LogFactory.getLog(StartupManager.class);

    public static final String FILE_OF_STARTUP_LISTENERS = "/WEB-INF/resources/startup_listeners.txt";

    private final List<ServletContextListener> initializeList = new ArrayList<ServletContextListener>();

    /**
     * These can be instance variables without risk, since contextInitialized()
     * will only be called once per instance.
     */
    private ServletContext ctx;
    private StartupStatus ss;

    /**
     * Build a list of the listeners, and run contextInitialized() on each of
     * them, at least until we get a fatal error.
     * 
     * Each step of this should handle its own exceptions, but we'll wrap the
     * whole thing in a try/catch just in case.
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ctx = sce.getServletContext();
        ss = StartupStatus.getBean(ctx);

        try {
            findAndInstantiateListeners();

            for (ServletContextListener listener : initializeList) {
                if (ss.isStartupAborted()) {
                    ss.listenerNotExecuted(listener);
                } else {
                    initialize(listener, sce);
                }
            }
            log.info("Called 'contextInitialized' on all listeners.");
        } catch (Exception e) {
            ss.fatal(this, "Startup threw an unexpected exception.", e);
            log.error("Startup threw an unexpected exception.", e);
        } catch (Throwable t) {
            log.fatal("Startup threw an unexpected error.", t);
            throw t;
        }
    }

    /**
     * Read the file and instantiate build a list of listener instances.
     * 
     * If there is a problem, it will occur and be handled in a sub-method.
     */
    private void findAndInstantiateListeners() {
        List<String> classNames = readFileOfListeners();

        for (String className : classNames) {
            ServletContextListener listener = instantiateListener(className);
            if (listener != null) {
                initializeList.add(listener);
            }
        }

        checkForDuplicateListeners();
    }

    /**
     * Read the names of the listener classes.
     * 
     * If there is a problem, set a fatal error, and return an empty list.
     */
    private List<String> readFileOfListeners() {
        List<String> list = new ArrayList<String>();

        InputStream is = null;
        BufferedReader br = null;
        try {
            is = ctx.getResourceAsStream(FILE_OF_STARTUP_LISTENERS);
            br = new BufferedReader(new InputStreamReader(is));

            String line;
            while (null != (line = br.readLine())) {
                String trimmed = line.trim();
                if (!trimmed.isEmpty() && !trimmed.startsWith("#")) {
                    list.add(trimmed);
                }
            }
        } catch (NullPointerException e) {
            ss.fatal(this, "Unable to locate the list of startup listeners: " + FILE_OF_STARTUP_LISTENERS);
        } catch (IOException e) {
            ss.fatal(this, "Failed while processing the list of startup listeners:  " + FILE_OF_STARTUP_LISTENERS,
                    e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    log.error(e);
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    log.error(e);
                }
            }
        }

        log.debug("Classnames of listeners = " + list);
        return list;
    }

    /**
     * Instantiate a context listener from this class name.
     * 
     * If there is a problem, set a fatal error, and return null.
     */
    private ServletContextListener instantiateListener(String className) {
        try {
            Class<?> c = Class.forName(className);
            Object o = c.newInstance();
            return (ServletContextListener) o;
        } catch (ClassCastException e) {
            ss.fatal(this, "Instance of '" + className + "' is not a ServletContextListener", e);
            return null;
        } catch (Exception e) {
            ss.fatal(this, "Failed to instantiate listener: '" + className + "'", e);
            return null;
        } catch (ExceptionInInitializerError e) {
            ss.fatal(this, "Failed to instantiate listener: '" + className + "'", e);
            return null;
        }
    }

    /**
     * Call contextInitialized() on the listener.
     * 
     * If there is an unexpected exception, set a fatal error.
     */
    private void initialize(ServletContextListener listener, ServletContextEvent sce) {
        try {
            log.debug("Initializing '" + listener.getClass().getName() + "'");
            listener.contextInitialized(sce);
            ss.listenerExecuted(listener);
        } catch (Exception e) {
            ss.fatal(listener, "Threw unexpected exception", e);
        } catch (Throwable t) {
            log.fatal(listener + " Threw unexpected error", t);
            throw t;
        }
    }

    /**
     * If we have more than one listener from the same class, set a fatal error.
     */
    private void checkForDuplicateListeners() {
        for (int i = 0; i < initializeList.size(); i++) {
            for (int j = i + 1; j < initializeList.size(); j++) {
                ServletContextListener iListener = initializeList.get(i);
                ServletContextListener jListener = initializeList.get(j);
                if (iListener.getClass().equals(jListener.getClass())) {
                    ss.fatal(this,
                            ("File contains duplicate listener classes: '" + iListener.getClass().getName() + "'"));
                }
            }
        }
    }

    /**
     * Notify the listeners that the context is being destroyed, in the reverse
     * order from how they were notified at initialization.
     */
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        List<ServletContextListener> destroyList = new ArrayList<ServletContextListener>(initializeList);
        Collections.reverse(destroyList);

        for (ServletContextListener listener : destroyList) {
            try {
                log.debug("Destroying '" + listener.getClass().getName() + "'");
                listener.contextDestroyed(sce);
            } catch (Exception e) {
                log.error("Unexpected exception from contextDestroyed() on '" + listener.getClass().getName() + "'",
                        e);
            } catch (Throwable t) {
                log.fatal("Unexpected error from contextDestroyed() on '" + listener.getClass().getName() + "'", t);
                throw t;
            }
        }
        log.info("Called 'contextDestroyed' on all listeners.");
    }

}