diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/PermissionSetsLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/PermissionSetsLoader.java index 32f8f6519..0e0723180 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/PermissionSetsLoader.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/PermissionSetsLoader.java @@ -17,7 +17,7 @@ import com.hp.hpl.jena.shared.Lock; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** * Load the initial configuration of PermissionSets and Permissions. @@ -38,10 +38,7 @@ public class PermissionSetsLoader implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); - - if (AbortStartup.isStartupAborted(ctx)) { - return; - } + StartupStatus ss = StartupStatus.getBean(ctx); try { String ns = ConfigurationProperties.getBean(ctx).getProperty( @@ -57,8 +54,7 @@ public class PermissionSetsLoader implements ServletContextListener { wrapper.createPermissionSet(URI_DBA, "Site Admin"); } catch (Exception e) { log.error("could not run PermissionSetsLoader" + e); - AbortStartup.abortStartup(ctx); - throw new RuntimeException(e); + ss.fatal(this, "could not run PermissionSetsLoader" + e); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java index 093bb07cd..c5c0d533c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java @@ -21,7 +21,7 @@ import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator; import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** * If the user has an IsRootUser identifier, they can do anything! @@ -64,10 +64,7 @@ public class RootUserPolicy implements PolicyIface { @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); - - if (AbortStartup.isStartupAborted(ctx)) { - return; - } + StartupStatus ss = StartupStatus.getBean(ctx); try { UserAccountsDao uaDao = getUserAccountsDao(ctx); @@ -82,8 +79,8 @@ public class RootUserPolicy implements PolicyIface { } catch (Exception e) { log.error("could not run " + this.getClass().getSimpleName() + ": " + e); - AbortStartup.abortStartup(ctx); - throw new RuntimeException(e); + ss.fatal(this, "could not run " + this.getClass().getSimpleName() + + ": " + e); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelper.java index ba230dbba..1daa2a900 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelper.java @@ -27,7 +27,7 @@ import com.hp.hpl.jena.shared.Lock; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** * Assists the role-based policies in determining whether a property or resource @@ -342,10 +342,7 @@ public class PropertyRestrictionPolicyHelper { @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); - - if (AbortStartup.isStartupAborted(ctx)) { - return; - } + StartupStatus ss = StartupStatus.getBean(ctx); try { OntModel model = (OntModel) ctx.getAttribute("jenaOntModel"); @@ -360,8 +357,8 @@ public class PropertyRestrictionPolicyHelper { } catch (Exception e) { log.error("could not run PropertyRestrictionPolicyHelper$Setup: " + e); - AbortStartup.abortStartup(ctx); - throw new RuntimeException(e); + ss.fatal(this, "could not run PropertyRestrictionPolicyHelper$Setup: " + + e); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/setup/CommonPolicyFamilySetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/setup/CommonPolicyFamilySetup.java index c1d394e00..670146044 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/setup/CommonPolicyFamilySetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/setup/CommonPolicyFamilySetup.java @@ -17,7 +17,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.policy.EditRestrictedDataByRoleLeve import edu.cornell.mannlib.vitro.webapp.auth.policy.SelfEditingPolicy; import edu.cornell.mannlib.vitro.webapp.auth.policy.ServletPolicyList; import edu.cornell.mannlib.vitro.webapp.auth.policy.UseRestrictedPagesByRoleLevelPolicy; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** * Set up the common policy family, with Identifier factory. @@ -29,10 +29,7 @@ public class CommonPolicyFamilySetup implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); - - if (AbortStartup.isStartupAborted(ctx)) { - return; - } + StartupStatus ss = StartupStatus.getBean(ctx); try { ServletPolicyList.addPolicy(ctx, @@ -54,8 +51,8 @@ public class CommonPolicyFamilySetup implements ServletContextListener { } catch (Exception e) { log.error("could not run " + this.getClass().getSimpleName() + ": " + e); - AbortStartup.abortStartup(ctx); - throw new RuntimeException(e); + ss.fatal(this, "could not run " + this.getClass().getSimpleName() + ": " + + e); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSetup.java index 4cdfe55bc..82318a4de 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSetup.java @@ -18,7 +18,7 @@ import javax.servlet.ServletContextListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** * Reads the configuration properties from a file and stores them in the servlet @@ -79,18 +79,20 @@ public class ConfigurationPropertiesSetup implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { - if (AbortStartup.isStartupAborted(sce.getServletContext())) { - return; - } - ServletContext ctx = sce.getServletContext(); + StartupStatus ss = StartupStatus.getBean(ctx); try { InputStream stream = null; try { stream = locatePropertiesFile(); - ConfigurationProperties.setBean(ctx, - new ConfigurationPropertiesImpl(stream)); + + ConfigurationPropertiesImpl bean = new ConfigurationPropertiesImpl( + stream); + ConfigurationProperties.setBean(ctx, bean); + + ss.info(this, "Loaded " + bean.getPropertyMap().size() + + " properties."); } finally { if (stream != null) { try { @@ -102,8 +104,7 @@ public class ConfigurationPropertiesSetup implements ServletContextListener { } } catch (Exception e) { log.error(e, e); - AbortStartup.abortStartup(ctx); - throw new RuntimeException(e); + ss.fatal(this, e.getMessage(), e); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/RevisionInfoSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/RevisionInfoSetup.java index e23191c1d..5220e39d8 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/RevisionInfoSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/RevisionInfoSetup.java @@ -26,6 +26,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean.LevelRevisionInfo; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** *
@@ -72,6 +73,7 @@ public class RevisionInfoSetup implements ServletContextListener {
 			bean = parseRevisionInformation(lines);
 		} catch (Exception e) {
 			log.error(e, e);
+			StartupStatus.getBean(context).warning(this, e.getMessage(), e);
 			bean = DUMMY_BEAN;
 		}
 
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerSetup.java
index fbe60b38a..09bc6e9e8 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerSetup.java
@@ -11,20 +11,13 @@ import javax.servlet.ServletContextListener;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup;
 import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel;
-import freemarker.template.Configuration;
 
 public class FreemarkerSetup implements ServletContextListener {
     
     private static final Log log = LogFactory.getLog(FreemarkerSetup.class);
 
 	public void contextInitialized(ServletContextEvent event) {	
-
-        if (AbortStartup.isStartupAborted(event.getServletContext())) {
-            return;
-        }
-	    
 		ServletContext sc = event.getServletContext();	
 		sc.setAttribute("themeToConfigMap", new HashMap());
         BaseTemplateModel.setServletContext(sc);
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupCache.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupCache.java
index a77910da2..2a50f82dd 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupCache.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupCache.java
@@ -16,7 +16,6 @@ import javax.servlet.ServletContextListener;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import com.hp.hpl.jena.ontology.Individual;
 import com.hp.hpl.jena.ontology.OntModel;
 import com.hp.hpl.jena.rdf.listeners.StatementListener;
 import com.hp.hpl.jena.rdf.model.ResourceFactory;
@@ -34,7 +33,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
 import edu.cornell.mannlib.vitro.webapp.dao.filtering.WebappDaoFactoryFiltering;
 import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilterUtils;
 import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters;
-import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup;
+import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
 
 public class VClassGroupCache {
     private static final Log log = LogFactory.getLog(VClassGroupCache.class);
@@ -69,7 +68,7 @@ public class VClassGroupCache {
         this.context = context;
         this._groupList = null;
 
-        if (AbortStartup.isStartupAborted(context)) {
+        if (StartupStatus.getBean(context).isStartupAborted()) {
             _cacheRebuildThread = null;
             return;
         }
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java
index 8eaac0efb..f440e3978 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java
@@ -17,7 +17,7 @@ import org.apache.commons.logging.LogFactory;
 
 import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
 import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
-import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup;
+import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
 
 /**
  * A factory that creates Freemarker-based email messages.
@@ -154,18 +154,25 @@ public class FreemarkerEmailFactory {
 		@Override
 		public void contextInitialized(ServletContextEvent sce) {
 			ServletContext ctx = sce.getServletContext();
-
-			if (AbortStartup.isStartupAborted(ctx)) {
-				return;
-			}
+			StartupStatus ss = StartupStatus.getBean(ctx);
 
 			try {
-				ctx.setAttribute(ATTRIBUTE_NAME,
-						new FreemarkerEmailFactory(ctx));
+				FreemarkerEmailFactory factory = new FreemarkerEmailFactory(ctx);
+				ctx.setAttribute(ATTRIBUTE_NAME, factory);
+
+				if (factory.isConfigured()) {
+					ss.info(this, "The system is configured to "
+							+ "send mail to users.");
+				} else {
+					ss.info(this, "Configuration parameters are missing: "
+							+ "the system will not send mail to users.");
+				}
 			} catch (Exception e) {
 				log.error(e, e);
-				AbortStartup.abortStartup(ctx);
-				throw new RuntimeException(e);
+				ss.warning(this,
+						"Failed to initialize FreemarkerEmailFactory. "
+								+ "The system will not be able to send email "
+								+ "to users.", e);
 			}
 		}
 
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/backend/FileStorageSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/backend/FileStorageSetup.java
index ca99c6e7c..221d8fa4d 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/backend/FileStorageSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/backend/FileStorageSetup.java
@@ -15,6 +15,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
+import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
 
 /**
  * Initializes the file storage system, and stores a reference in the servlet
@@ -50,15 +51,18 @@ public class FileStorageSetup implements ServletContextListener {
 	 */
 	@Override
 	public void contextInitialized(ServletContextEvent sce) {
+		ServletContext ctx = sce.getServletContext();
+		StartupStatus ss = StartupStatus.getBean(ctx);
+
 		try {
 			File baseDirectory = figureBaseDir(sce);
 			Collection fileNamespace = confirmDefaultNamespace(sce);
 			FileStorage fs = new FileStorageImpl(baseDirectory, fileNamespace);
 
-			ServletContext sc = sce.getServletContext();
-			sc.setAttribute(ATTRIBUTE_NAME, fs);
+			ctx.setAttribute(ATTRIBUTE_NAME, fs);
 		} catch (Exception e) {
 			log.fatal("Failed to initialize the file system.", e);
+			ss.fatal(this, "Failed to initialize the file system.", e);
 		}
 	}
 
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/SolrSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/SolrSetup.java
index 506b96dde..a85c28df6 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/SolrSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/SolrSetup.java
@@ -38,7 +38,7 @@ import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalURIsForObjectP
 import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalURIsForTypeStatements;
 import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
 import edu.cornell.mannlib.vitro.webapp.search.indexing.SearchReindexingListener;
-import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup;
+import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
 
 public class SolrSetup implements javax.servlet.ServletContextListener{   
     private static final Log log = LogFactory.getLog(SolrSetup.class.getName());
@@ -47,12 +47,10 @@ public class SolrSetup implements javax.servlet.ServletContextListener{
     
     @Override
     public void contextInitialized(ServletContextEvent sce) {        
-        if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-                              
+    	ServletContext context = sce.getServletContext();
+		StartupStatus ss = StartupStatus.getBean(context);
+		
         try {        
-            ServletContext context = sce.getServletContext();
             
             /* setup the http connection with the solr server */
             String solrServerUrl = ConfigurationProperties.getBean(sce).getProperty("vitro.local.solr.url");
@@ -122,8 +120,10 @@ public class SolrSetup implements javax.servlet.ServletContextListener{
             ModelContext.registerListenerForChanges(ctx, srl);
             
             log.info("Setup of Solr index completed.");   
+            ss.info(this, "Setup of Solr index completed.");   
         } catch (Throwable e) {
             log.error("could not setup local solr server",e);
+            ss.fatal(this, "could not setup local solr server",e);
         }
        
     }
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AbortStartup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AbortStartup.java
deleted file mode 100644
index c06685c2d..000000000
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AbortStartup.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/* $This file is distributed under the terms of the license in /doc/license.txt$ */
-
-package edu.cornell.mannlib.vitro.webapp.servlet.setup;
-
-import javax.servlet.ServletContext;
-
-/**
- * Provide a mechanism so a ServletContextListener can set a flag that tells
- * other ServletContextListeners not to run.
- * 
- * The listener that detects a problem should still throw an exception, so
- * Tomcat will declare that the startup has failed and mark the application as
- * not runnable. However, Tomcat will still run the other listeners before
- * giving up. Hence, the need for this flag.
- * 
- * If the other listeners are looking for this flag, they can (and should)
- * decide to simply exit rather than attempting to initialize.
- */
-public class AbortStartup {
-
-    private static final String ATTRIBUTE_NAME = AbortStartup.class.getName();
-    
-    /**
-     * Sets a context attribute to prevent other context listeners from running.
-     */
-    public static void abortStartup(ServletContext context) {
-        context.setAttribute(ATTRIBUTE_NAME, new Boolean(true));
-    }
-    
-    /**
-     * Checks whether a previous context listener has caused startup to be aborted.
-     */
-    public static boolean isStartupAborted(ServletContext context) {
-        return (context.getAttribute(ATTRIBUTE_NAME) != null);
-    }
-    
-}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AssembleModelsSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AssembleModelsSetup.java
index 237f55311..e9dbc9f20 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AssembleModelsSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AssembleModelsSetup.java
@@ -43,10 +43,6 @@ public class AssembleModelsSetup implements ServletContextListener {
 	
 	public void contextInitialized(ServletContextEvent sce) {
 	    
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-	        return;
-	    }
-	    
 		OntModel jenaOntModel = null;
 		try {
 			jenaOntModel = (OntModel) sce.getServletContext().getAttribute("baseOntModel");
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AttachSubmodels.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AttachSubmodels.java
index 60044df26..8cce8d675 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AttachSubmodels.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AttachSubmodels.java
@@ -31,10 +31,6 @@ public class AttachSubmodels implements ServletContextListener {
 	public void contextInitialized( ServletContextEvent sce ) {
 	    
 	    ServletContext ctx = sce.getServletContext();
-		if (AbortStartup.isStartupAborted(ctx)) {
-            return;
-        }
-		
 	    
         if (true) {
             (new FileGraphSetup()).contextInitialized(sce);
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/DefaultThemeSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/DefaultThemeSetup.java
index dc953a0b6..adaad7662 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/DefaultThemeSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/DefaultThemeSetup.java
@@ -14,12 +14,8 @@ import edu.cornell.mannlib.vitro.webapp.utils.ThemeUtils;
 public class DefaultThemeSetup implements ServletContextListener {
 	
 	// Set default theme based on themes present on the file system
+	@Override
 	public void contextInitialized(ServletContextEvent event) {
-
-	    if (AbortStartup.isStartupAborted(event.getServletContext())) {
-            return;
-        }
-	    
     	// Find the themes directory in the file system
 		ServletContext sc = event.getServletContext();		
     	boolean doSort = true;
@@ -36,9 +32,9 @@ public class DefaultThemeSetup implements ServletContextListener {
         String defaultThemeDir = "themes/" + defaultTheme + "/";
         // Define as a static variable of Portal so getThemeDir() method of portal can access it.
         ApplicationBean.DEFAULT_THEME_DIR_FROM_CONTEXT = defaultThemeDir;
-        
 	}
 
+	@Override
 	public void contextDestroyed(ServletContextEvent event) {
 		// nothing to do here
 	}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java
index b77aa010a..8a33f5979 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java
@@ -43,10 +43,6 @@ public class FileGraphSetup implements ServletContextListener {
 		
 	public void contextInitialized(ServletContextEvent sce) {
 		
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-	    
 		boolean aboxChanged = false; // indicates whether any ABox file graph model has changed
 		boolean tboxChanged = false; // indicates whether any TBox file graph model has changed
 		OntModelSelector baseOms = null;
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/HeapDefragement.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/HeapDefragement.java
index 50ea33181..c17b513b0 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/HeapDefragement.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/HeapDefragement.java
@@ -25,11 +25,6 @@ public class HeapDefragement implements ServletContextListener {
     
     @Override
     public void contextInitialized(ServletContextEvent arg0) {
-        
-        if (AbortStartup.isStartupAborted(arg0.getServletContext())) {
-            return;
-        }
-        
         try{
             log.info("Calling System.gc() to defragement the heap.");
             long start = System.currentTimeMillis();
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetup.java
index 5df68b789..d9ec1fb14 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetup.java
@@ -2,7 +2,6 @@
 
 package edu.cornell.mannlib.vitro.webapp.servlet.setup;
 
-import java.io.IOException;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -52,7 +51,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelectorImpl;
 import edu.cornell.mannlib.vitro.webapp.dao.jena.VitroJenaModelMaker;
 import edu.cornell.mannlib.vitro.webapp.dao.jena.VitroJenaSDBModelMaker;
 import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactorySDB;
-import edu.cornell.mannlib.vitro.webapp.ontology.update.KnowledgeBaseUpdater;
+import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
 import edu.cornell.mannlib.vitro.webapp.utils.jena.InitialJenaModelUtils;
 
 public class JenaDataSourceSetup extends JenaDataSourceSetupBase implements javax.servlet.ServletContextListener {
@@ -61,12 +60,8 @@ public class JenaDataSourceSetup extends JenaDataSourceSetupBase implements java
     
     @Override
 	public void contextInitialized(ServletContextEvent sce) {
-    	
     	ServletContext ctx = sce.getServletContext();
-        
-		if (AbortStartup.isStartupAborted(ctx)) {
-            return;
-        }
+    	StartupStatus ss = StartupStatus.getBean(ctx);
         
         try {
         	long startTime = System.currentTimeMillis();
@@ -75,18 +70,11 @@ public class JenaDataSourceSetup extends JenaDataSourceSetupBase implements java
         			" seconds to set up SDB store");
         } catch (SQLException sqle) {   
             // SQL exceptions are fatal and should halt startup
-            AbortStartup.abortStartup(ctx);
             log.error("Error using SQL database; startup aborted.", sqle);
-            // print to catalina.out for good measure
-            System.out.println("Error using SQL database; startup aborted.");
-            sqle.printStackTrace();
-            throw new Error(this.getClass().getName() + "failed");
+            ss.fatal(this, "Error using SQL database; startup aborted.", sqle);
         } catch (Throwable t) {
             log.error("Throwable in " + this.getClass().getName(), t);
-            // printing the error because Tomcat doesn't print context listener
-            // errors the same way it prints other errors at startup
-            t.printStackTrace();
-            throw new Error(this.getClass().getName() + "failed");
+            ss.fatal(this, "Throwable in " + this.getClass().getName(), t);
         }
         
     } 
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java
index bcffb1617..36d451301 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java
@@ -23,6 +23,7 @@ import com.hp.hpl.jena.rdf.model.Model;
 import com.hp.hpl.jena.rdf.model.ModelFactory;
 
 import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelSynchronizer;
+import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
 
 public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase 
                                            implements ServletContextListener {
@@ -33,11 +34,8 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase
 	@Override	
 	public void contextInitialized(ServletContextEvent sce) {	    
         ServletContext ctx = sce.getServletContext();
+        StartupStatus ss = StartupStatus.getBean(ctx);
 		
-	    if (AbortStartup.isStartupAborted(ctx)) {
-            return;
-        }
-        
         // user accounts Model
         try {
         	Model userAccountsDbModel = makeDBModelFromConfigurationProperties(
@@ -59,6 +57,7 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase
         	}
         } catch (Throwable t) {
         	log.error("Unable to load user accounts model from DB", t);
+        	ss.fatal(this, "Unable to load user accounts model from DB", t);
         }
              
         // display, editing and navigation Model 
@@ -77,6 +76,7 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase
 	    	initializeDisplayLoadedAtStartup(ctx, displayModel);		    	
 	    } catch (Throwable t) {
 	    	log.error("Unable to load user application configuration model", t);
+	    	ss.fatal(this, "Unable to load user application configuration model", t);
 	    }
 	    
 	    //display tbox - currently reading in every time
@@ -94,6 +94,7 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase
 	    	log.debug("Loaded file " + APPPATH_LOAD + "displayTBOX.n3 into display tbox model");
 	    } catch (Throwable t) {
 	    	log.error("Unable to load user application configuration model TBOX", t);
+	    	ss.fatal(this, "Unable to load user application configuration model TBOX", t);
 	    }
 	    
 	    //Display Display model, currently empty, create if doesn't exist but no files to load
@@ -112,6 +113,7 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase
 	    	log.debug("Loaded file " + APPPATH_LOAD + "displayDisplay.n3 into display display model");
 	    } catch (Throwable t) {
 	    	log.error("Unable to load user application configuration model Display Model", t);
+	    	ss.fatal(this, "Unable to load user application configuration model Display Model", t);
 	    }
 	}
 	
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/NamespacePrefixMapSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/NamespacePrefixMapSetup.java
index 4dd388495..54dab91c1 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/NamespacePrefixMapSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/NamespacePrefixMapSetup.java
@@ -13,11 +13,6 @@ import com.hp.hpl.jena.rdf.model.Model;
 public class NamespacePrefixMapSetup implements ServletContextListener {
 	
 	public void contextInitialized(ServletContextEvent sce) {
-	    
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-	    
 		HashMap prefixToNamespace = new HashMap();
 		HashMap namespaceToPrefix = new HashMap();
 		Model model = (Model) sce.getServletContext().getAttribute("jenaOntModel");
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/NightlyDefragement.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/NightlyDefragement.java
index 3fb81b808..f23a6711b 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/NightlyDefragement.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/NightlyDefragement.java
@@ -61,11 +61,6 @@ public class NightlyDefragement implements ServletContextListener, Runnable {
     
     @Override
     public void contextInitialized(ServletContextEvent arg0) {
-        
-        if (AbortStartup.isStartupAborted(arg0.getServletContext())) {
-            return;
-        }
-        
         lastRun = new DateTime().minusHours( 400 );
         if( nightlyDefragement != null ){
             log.warn("NightlyDefragement listener has already been setup. Check your web.xml for duplicate listeners.");            
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java
index c9efe26f1..5a3930c10 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java
@@ -22,11 +22,6 @@ public class PelletReasonerSetup implements ServletContextListener {
 	
 	@Override
 	public void contextInitialized(ServletContextEvent sce) {
-		
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-
 	    if (true) {
             (new SimpleReasonerSetup()).contextInitialized(sce);
             return;
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupComplete.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupComplete.java
index b096a49d8..39e8f83af 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupComplete.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupComplete.java
@@ -20,11 +20,6 @@ public class PelletReasonerSetupComplete implements ServletContextListener {
 	private static final Log log = LogFactory.getLog(PelletReasonerSetupComplete.class.getName());
 	
 	public void contextInitialized(ServletContextEvent sce) {
-		
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-	    
 		try {	
 			
     		OntModel memoryModel = (OntModel) sce.getServletContext().getAttribute("jenaOntModel");
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupPseudocomplete.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupPseudocomplete.java
index 15438580c..cb93eaf69 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupPseudocomplete.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupPseudocomplete.java
@@ -20,11 +20,6 @@ public class PelletReasonerSetupPseudocomplete implements ServletContextListener
 	private static final Log log = LogFactory.getLog(PelletReasonerSetupComplete.class.getName());
 	
 	public void contextInitialized(ServletContextEvent sce) {
-		
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-	    
 		try {	
 			
     		OntModel memoryModel = (OntModel) sce.getServletContext().getAttribute("jenaOntModel");
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupPseudocompleteIgnoreDataproperties.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupPseudocompleteIgnoreDataproperties.java
index 8cfee3294..02bd5b098 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupPseudocompleteIgnoreDataproperties.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetupPseudocompleteIgnoreDataproperties.java
@@ -21,13 +21,7 @@ public class PelletReasonerSetupPseudocompleteIgnoreDataproperties implements
 	private static final Log log = LogFactory.getLog(PelletReasonerSetupPseudocompleteIgnoreDataproperties.class.getName());
 	
 	public void contextInitialized(ServletContextEvent sce) {
-	
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-	    
 		try {
-		
 			OntModel memoryModel = (OntModel) sce.getServletContext().getAttribute("jenaOntModel");
 			OntModel baseModel = (OntModel) sce.getServletContext().getAttribute("baseOntModel");
 			OntModel inferenceModel = (OntModel) sce.getServletContext().getAttribute("inferenceOntModel");
@@ -57,7 +51,6 @@ public class PelletReasonerSetupPseudocompleteIgnoreDataproperties implements
 		} catch (Throwable t) {
 			t.printStackTrace();
 		}
-		
 	}
 	
 	public void contextDestroyed(ServletContextEvent arg0) {
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RunSparqlConstructs.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RunSparqlConstructs.java
index db416e963..b76bebb85 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RunSparqlConstructs.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RunSparqlConstructs.java
@@ -41,13 +41,7 @@ public class RunSparqlConstructs implements ServletContextListener {
 	private static Random random = new Random(System.currentTimeMillis());
 	
 	public void contextInitialized(ServletContextEvent sce) {
-		
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-	    
 		try {
-		
 			WebappDaoFactory wadf = (WebappDaoFactory) sce.getServletContext().getAttribute("webappDaoFactory");
 			String namespace = (wadf != null && wadf.getDefaultNamespace() != null) 
 				? wadf.getDefaultNamespace() : DEFAULT_DEFAULT_NAMESPACE;
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java
index 9022fc7a0..38e1e9a5b 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java
@@ -34,11 +34,6 @@ public class SimpleReasonerSetup implements ServletContextListener {
 
 	@Override
 	public void contextInitialized(ServletContextEvent sce) {
-	    
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-	    
 		try {	
 		    // set up Pellet reasoning for the TBox	
 			
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java
index 3f4fb2efa..6159772ca 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java
@@ -68,13 +68,7 @@ public class UpdateKnowledgeBase implements ServletContextListener {
 	private static final String NEW_TBOX_ANNOTATIONS_DIR = "/WEB-INF/ontologies/user/tbox/";
 	
 	public void contextInitialized(ServletContextEvent sce) {
-				
-	    if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-            return;
-        }
-	    
 		try {
-
 			ServletContext ctx = sce.getServletContext();
 			
 			String logFileName =  DATA_DIR + LOG_DIR + timestampedFileName("knowledgeBaseUpdate", "log");
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUploadedFiles.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUploadedFiles.java
index 06d698355..079dfdac0 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUploadedFiles.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUploadedFiles.java
@@ -20,6 +20,7 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
 import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
 import edu.cornell.mannlib.vitro.webapp.filestorage.updater.FileStorageAliasAdder;
 import edu.cornell.mannlib.vitro.webapp.filestorage.updater.FileStorageUpdater;
+import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
 
 /**
  * Check that the conditions are met for updating uploaded files. If everything
@@ -48,14 +49,9 @@ public class UpdateUploadedFiles implements ServletContextListener {
 	 */
 	@Override
 	public void contextInitialized(ServletContextEvent sce) {
-
-		if (AbortStartup.isStartupAborted(sce.getServletContext())) {
-			return;
-		}
-
+		ServletContext ctx = sce.getServletContext();
+		
 		try {
-			ServletContext ctx = sce.getServletContext();
-
 			WebappDaoFactory wadf = (WebappDaoFactory) ctx
 					.getAttribute("assertionsWebappDaoFactory");
 			if (wadf == null) {
@@ -142,6 +138,7 @@ public class UpdateUploadedFiles implements ServletContextListener {
 			fsaa.update();
 		} catch (Exception e) {
 			log.fatal("Unknown problem", e);
+			StartupStatus.getBean(ctx).fatal(this, "Unknown problem", e);
 		}
 	}
 }
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUserAccounts.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUserAccounts.java
index 2ad93ec29..df5fbb814 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUserAccounts.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUserAccounts.java
@@ -37,6 +37,7 @@ import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
 import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
 import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
 import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext;
+import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
 
 /**
  * Convert any existing User resources (up to rel 1.2) in the UserAccounts Model
@@ -60,18 +61,16 @@ public class UpdateUserAccounts implements ServletContextListener {
 	@Override
 	public void contextInitialized(ServletContextEvent sce) {
 		ServletContext ctx = sce.getServletContext();
-		if (AbortStartup.isStartupAborted(ctx)) {
-			return;
-		}
-
+		StartupStatus ss = StartupStatus.getBean(ctx);
+		
 		try {
 			Updater updater = new Updater(ctx);
 			if (updater.isThereAnythingToDo()) {
 				updater.update();
 			}
 		} catch (Exception e) {
-			AbortStartup.abortStartup(ctx);
 			log.fatal("Failed to update user accounts information", e);
+			ss.fatal(this, "Failed to update user accounts information", 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 447a2addc..5f0c3e644 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupStatus.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupStatus.java
@@ -11,11 +11,16 @@ import java.util.List;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletContextListener;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 /**
  * Accumulates a list of messages from the StartupManager, and from the context
  * listeners that the run during startup.
  */
 public class StartupStatus {
+	private static final Log log = LogFactory.getLog(StartupStatus.class);
+
 	private static final String ATTRIBUTE_NAME = "STARTUP_STATUS";
 
 	// ----------------------------------------------------------------------
@@ -143,20 +148,67 @@ public class StartupStatus {
 		private final String message;
 		private final String cause;
 
+		private boolean unexpectedArguments;
+
 		public StatusItem(Level level, ServletContextListener source,
 				String message, Throwable cause) {
-			this.level = level;
-			this.sourceName = source.getClass().getName();
-			this.shortSourceName = source.getClass().getSimpleName();
+			this.level = figureLevel(level);
+			this.sourceName = figureSourceName(source);
+			this.shortSourceName = figureShortSourceName(source);
 			this.message = message;
+			this.cause = figureCauseString(cause);
 
-			if (cause == null) {
-				this.cause = "";
+			if (unexpectedArguments) {
+				log.error("Unexpected arguments to "
+						+ StatusItem.class.getName() + ": level=" + level
+						+ ", source=" + source + ", message=" + message
+						+ ", cause=" + cause);
+			}
+		}
+
+		/** Level should never be null: we have a problem. */
+		private Level figureLevel(Level newLevel) {
+			if (newLevel == null) {
+				unexpectedArguments = true;
+				return Level.FATAL;
+			} else {
+				return newLevel;
+			}
+		}
+
+		private String figureSourceName(ServletContextListener source) {
+			if (source == null) {
+				unexpectedArguments = true;
+				return "UNKNOWN SOURCE";
+			} else {
+				return source.getClass().getName();
+			}
+		}
+
+		/**
+		 * Don't just use getSimpleName(): on an inner class we'd like to see
+		 * the parent also.
+		 */
+		private String figureShortSourceName(ServletContextListener source) {
+			if (source == null) {
+				unexpectedArguments = true;
+				return "UNKNOWN_SOURCE";
+			} else {
+				String sourceClassName = source.getClass().getName();
+				int lastPeriodHere = sourceClassName.lastIndexOf('.');
+				return sourceClassName.substring(lastPeriodHere + 1);
+			}
+		}
+
+		/** Cause may be null - that's not unexpected. */
+		private String figureCauseString(Throwable newCause) {
+			if (newCause == null) {
+				return "";
 			} else {
 				StringWriter sw = new StringWriter();
 				PrintWriter pw = new PrintWriter(sw);
-				cause.printStackTrace(pw);
-				this.cause = sw.toString();
+				newCause.printStackTrace(pw);
+				return sw.toString();
 			}
 		}