From 350faa50fac8f4bf770038d6db938669b51d7f33 Mon Sep 17 00:00:00 2001 From: j2blake Date: Wed, 23 Nov 2011 20:10:53 +0000 Subject: [PATCH] Make StartupStatus thread-safe, so we can add items at any time. --- .../vitro/webapp/startup/StartupStatus.java | 106 ++++++++++++++---- 1 file changed, 84 insertions(+), 22 deletions(-) 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 f84c25b03..0a0601910 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupStatus.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/startup/StartupStatus.java @@ -5,7 +5,6 @@ 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; import javax.servlet.ServletContext; @@ -17,6 +16,9 @@ import org.apache.commons.logging.LogFactory; /** * Accumulates a list of messages from the StartupManager, and from the context * listeners that the run during startup. + * + * This is thread-safe, with immutable items in the list and synchronized access + * to the list. */ public class StartupStatus { private static final Log log = LogFactory.getLog(StartupStatus.class); @@ -45,7 +47,7 @@ public class StartupStatus { // methods to set status - note that these write to the log also. // ---------------------------------------------------------------------- - private List itemList = new ArrayList(); + private SynchronizedStatusItemList itemList = new SynchronizedStatusItemList(); public void info(ServletContextListener listener, String message) { addItem(StatusItem.Level.INFO, listener, message, null); @@ -84,12 +86,10 @@ public class StartupStatus { /** Create a simple item for this listener if no other exists. */ public void listenerExecuted(ServletContextListener listener) { - for (StatusItem item : itemList) { - if (item.getSourceName().equals(listener.getClass().getName())) { - return; - } + List itemsForThisListener = getItemsForListener(listener); + if (itemsForThisListener.isEmpty()) { + addItem(StatusItem.Level.INFO, listener, "Ran successfully.", null); } - addItem(StatusItem.Level.INFO, listener, "Ran successfully.", null); } private void addItem(StatusItem.Level level, ServletContextListener source, @@ -133,33 +133,29 @@ public class StartupStatus { } public List getStatusItems() { - return Collections.unmodifiableList(itemList); + return itemList.filterItems(StatusItemFilter.ALL_ITEMS_FILTER); } public List getErrorItems() { - List list = new ArrayList(); - for (StatusItem item : itemList) { - if (item.level == StatusItem.Level.FATAL) { - list.add(item); - } - } - return list; + return itemList.filterItems(StatusItemFilter.ERROR_ITEMS_FILTER); } public List getWarningItems() { - List list = new ArrayList(); - for (StatusItem item : itemList) { - if (item.level == StatusItem.Level.WARNING) { - list.add(item); - } - } - return list; + return itemList.filterItems(StatusItemFilter.WARNING_ITEMS_FILTER); + } + + public List getItemsForListener(ServletContextListener listener) { + return itemList.filterItems(StatusItemFilter.listenerFilter(listener)); } // ---------------------------------------------------------------------- // helper classes // ---------------------------------------------------------------------- + /** + * An immutable item that can't throw an exception during construction and + * will always contain suitable, non-null values. + */ public static class StatusItem { public enum Level { INFO, WARNING, FATAL, NOT_EXECUTED @@ -257,4 +253,70 @@ public class StartupStatus { } + /** + * A filter class and some basic instances. + */ + private static abstract class StatusItemFilter { + public abstract boolean accept(StatusItem item); + + public static final StatusItemFilter ALL_ITEMS_FILTER = new StatusItemFilter() { + @Override + public boolean accept(StatusItem item) { + return true; + } + }; + + public static final StatusItemFilter ERROR_ITEMS_FILTER = new StatusItemFilter() { + @Override + public boolean accept(StatusItem item) { + return item.level == StatusItem.Level.FATAL; + } + }; + + public static final StatusItemFilter WARNING_ITEMS_FILTER = new StatusItemFilter() { + @Override + public boolean accept(StatusItem item) { + return item.level == StatusItem.Level.WARNING; + } + }; + + public static StatusItemFilter listenerFilter( + ServletContextListener listener) { + final String listenerName = listener.getClass().getName(); + + return new StatusItemFilter() { + @Override + public boolean accept(StatusItem item) { + return item.getSourceName().equals(listenerName); + } + }; + + } + } + + /** + * A list, with synchronized methods for adding to it, and for getting a + * filtered subset of it. + */ + private class SynchronizedStatusItemList { + private final List list = new ArrayList(); + + public void add(StatusItem item) { + synchronized (list) { + list.add(item); + } + } + + public List filterItems(StatusItemFilter filter) { + List filteredList = new ArrayList(); + synchronized (list) { + for (StatusItem item : list) { + if (filter.accept(item)) { + filteredList.add(item); + } + } + } + return filteredList; + } + } }