diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupManager.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupManager.java index 6c06f0a44..6c7310b9f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupManager.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupManager.java @@ -18,7 +18,16 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * TODO + * 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); @@ -175,8 +184,11 @@ public class StartupManager implements ServletContextListener { try { log.debug("Initializing '" + listener.getClass().getName() + "'"); listener.contextInitialized(sce); + ss.listenerExecuted(listener); } catch (Exception e) { ss.fatal(listener, "Threw unexpected exception", e); + log.error("Listener threw fatal exception: '" + + listener.getClass().getName() + "'", e); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupStatus.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupStatus.java index f28fe226e..447a2addc 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupStatus.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupStatus.java @@ -2,6 +2,8 @@ package edu.cornell.mannlib.vitro.webapp.startup; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -10,11 +12,16 @@ import javax.servlet.ServletContext; import javax.servlet.ServletContextListener; /** - * TODO + * Accumulates a list of messages from the StartupManager, and from the context + * listeners that the run during startup. */ public class StartupStatus { private static final String ATTRIBUTE_NAME = "STARTUP_STATUS"; + // ---------------------------------------------------------------------- + // static methods + // ---------------------------------------------------------------------- + public static StartupStatus getBean(ServletContext ctx) { StartupStatus ss; @@ -29,6 +36,10 @@ public class StartupStatus { return ss; } + // ---------------------------------------------------------------------- + // methods to set status + // ---------------------------------------------------------------------- + private List itemList = new ArrayList(); public void info(ServletContextListener listener, String message) { @@ -58,21 +69,22 @@ public class StartupStatus { addItem(StatusItem.Level.FATAL, listener, message, cause); } + /** Say that a previous fatal error prevented this listener from running. */ public void listenerNotExecuted(ServletContextListener listener) { - addItem(StatusItem.Level.NOT_EXECUTED, listener, "Not executed", null); + addItem(StatusItem.Level.NOT_EXECUTED, + listener, + "Not executed - startup was aborted by a previous fatal error.", + null); } - public boolean isStartupAborted() { + /** Create a simple item for this listener if no other exists. */ + public void listenerExecuted(ServletContextListener listener) { for (StatusItem item : itemList) { - if (item.level == StatusItem.Level.FATAL) { - return true; + if (item.getSourceName().equals(listener.getClass().getName())) { + return; } } - return false; - } - - public List getStatusItems() { - return Collections.unmodifiableList(itemList); + addItem(StatusItem.Level.INFO, listener, "Ran successfully.", null); } private void addItem(StatusItem.Level level, ServletContextListener source, @@ -80,22 +92,92 @@ public class StartupStatus { itemList.add(new StatusItem(level, source, message, cause)); } + // ---------------------------------------------------------------------- + // methods to query status + // ---------------------------------------------------------------------- + + public boolean allClear() { + return getErrorItems().isEmpty() && getWarningItems().isEmpty(); + } + + public boolean isStartupAborted() { + return !getErrorItems().isEmpty(); + } + + public List getStatusItems() { + return Collections.unmodifiableList(itemList); + } + + public List getErrorItems() { + List list = new ArrayList(); + for (StatusItem item : itemList) { + if (item.level == StatusItem.Level.FATAL) { + list.add(item); + } + } + return list; + } + + public List getWarningItems() { + List list = new ArrayList(); + for (StatusItem item : itemList) { + if (item.level == StatusItem.Level.WARNING) { + list.add(item); + } + } + return list; + } + + // ---------------------------------------------------------------------- + // helper classes + // ---------------------------------------------------------------------- + public static class StatusItem { public enum Level { INFO, WARNING, FATAL, NOT_EXECUTED } - final Level level; - final String sourceName; - final String message; - final Throwable cause; + private final Level level; + private final String sourceName; + private final String shortSourceName; + private final String message; + private final String cause; public StatusItem(Level level, ServletContextListener source, String message, Throwable cause) { this.level = level; this.sourceName = source.getClass().getName(); + this.shortSourceName = source.getClass().getSimpleName(); this.message = message; - this.cause = cause; + + if (cause == null) { + this.cause = ""; + } else { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + cause.printStackTrace(pw); + this.cause = sw.toString(); + } + } + + public Level getLevel() { + return level; + } + + public String getSourceName() { + return sourceName; + } + + public String getShortSourceName() { + return shortSourceName; + } + + public String getMessage() { + return message; + } + + public String getCause() { + return cause; } }