001: /* Copyright 2003, 2004 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal;
007:
008: import java.util.Collections;
009: import java.util.LinkedList;
010: import java.util.List;
011: import java.util.TreeMap;
012:
013: import org.jasig.portal.properties.PropertiesManager;
014:
015: /**
016: * A cache of recently reported PortalExceptions.
017: * @author Howard Gilbert
018: * @author andrew.petro@yale.edu
019: * @version $Revision: 34813 $
020: */
021: public class ProblemsTable {
022:
023: /** TreeMap from ErrorID Categories to TreeMaps.
024: * The enclosed TreeMaps map from Specifics (ErrorID subcategories)
025: * to CountID objects. The CountID objects cache the PortalExceptions
026: * that were in the Specific.
027: */
028: public static TreeMap registeredIds = new TreeMap();
029:
030: /**
031: * List of recently modified CountID instances.
032: */
033: public static LinkedList recentIds = new LinkedList();
034:
035: /**
036: * List of recently reported PortalExceptions, regardless of category.
037: */
038: private static LinkedList recentPortalExceptions = new LinkedList();
039:
040: /**
041: * The name of the PropertiesManager property the value of which should be the
042: * number of recent PortalExceptions you would like stored for each specific subcategory of ErrorID.
043: */
044: public static final String MAX_RECENT_ERRORS_PER_SPECIFIC_PROPERTY = "org.jasig.portal.ProblemsTable.maxRecentErrorsPerSpecific";
045:
046: /**
047: * The default number of recent PortalExceptions that will be stored for each specific subcategory of ErrorID
048: * in the case where the relevant property is not set.
049: */
050: private static final int DEFAULT_MAX_RECENT_PER_SPECIFIC = 10;
051:
052: /**
053: * The number of recent PortalExceptions that will be stored for each specific subcategory of ErrorID.
054: */
055: private static final int maxRecent = PropertiesManager
056: .getPropertyAsInt(MAX_RECENT_ERRORS_PER_SPECIFIC_PROPERTY,
057: DEFAULT_MAX_RECENT_PER_SPECIFIC);
058:
059: /**
060: * The name of the propertiesManager property the value of which should be the number of recent
061: * PortalExceptions you would like stored in the overall FIFO cache, regardless of ErrorID.
062: */
063: public static final String OVERALL_RECENT_ERRORS_PROPERTY = "org.jasig.portal.ProblemsTable.recentErrorsOverall";
064:
065: /**
066: * The default number of recent PortalExceptions that will be stored in the overall FIFO queue
067: * regardless of ErrorID, which will be used in the case where the relevant property is not set.
068: */
069: private static final int DEFAULT_OVERALL_RECENT_ERRORS_COUNT = 40;
070:
071: /**
072: * The number of recent PortalExceptions that will be stored in the overall FIFO queue
073: * regardless of ErrorID.
074: */
075: private static final int overallErrorsCount = PropertiesManager
076: .getPropertyAsInt(OVERALL_RECENT_ERRORS_PROPERTY,
077: DEFAULT_OVERALL_RECENT_ERRORS_COUNT);
078:
079: /**
080: * Add ErrorID to TreeMaps
081: *
082: * @param id ErrorID (ignored if duplicate)
083: */
084: public synchronized static void register(ErrorID id) {
085: if (id == null)
086: return;
087: String category = id.getCategory();
088: String specific = id.getSpecific();
089: TreeMap minor = (TreeMap) registeredIds.get(category);
090: if (minor == null) {
091: minor = new TreeMap();
092: registeredIds.put(category, minor);
093: }
094: if (!minor.containsKey(specific)) {
095: minor.put(specific, new CountID(id));
096: }
097: }
098:
099: /**
100: * Store a PortalException in the tables.
101: *
102: * @param pe PortalException to be tabulated
103: */
104: public synchronized static void store(PortalException pe) {
105: if (pe == null)
106: return; // bad argument
107: if (recentPortalExceptions.contains(pe))
108: return; // already recorded
109: ErrorID id = pe.getErrorID();
110: if (id == null)
111: return; // no ErrorID (Msg only PortalException)
112: String category = id.getCategory();
113: String specific = id.getSpecific();
114: TreeMap minor = (TreeMap) registeredIds.get(category);
115: if (minor == null)
116: return; // ErrorID not registered
117: CountID countid = (CountID) minor.get(specific);
118: if (countid == null)
119: return; // ErrorID not registered
120:
121: countid.count++;
122: countid.lastPortalException = pe;
123:
124: recentIds.remove(countid);
125: recentIds.addFirst(countid);
126: if (recentIds.size() > maxRecent)
127: recentIds.removeLast();
128:
129: // store this PortalException in the overall FIFO queue of recent PortalExceptions.
130: ProblemsTable.recentPortalExceptions.addFirst(pe);
131: if (ProblemsTable.recentPortalExceptions.size() > ProblemsTable.overallErrorsCount)
132: ProblemsTable.recentPortalExceptions.removeLast();
133: }
134:
135: /**
136: * Get an unmodifiable shallow copy of the list of recent PortalExceptions.
137: * @return an unmodifiable shallow copy of the list of recent PortalExceptions.
138: */
139: public synchronized static List getRecentPortalExceptions() {
140: return Collections
141: .unmodifiableList((List) ProblemsTable.recentPortalExceptions
142: .clone());
143: }
144:
145: }
146:
147: /**
148: * ErrorID tabulation class
149: *
150: * The TreeMaps yield an instance of this class
151: */
152: class CountID {
153: ErrorID errorID = null;
154: int count = 0;
155: PortalException lastPortalException = null;
156:
157: CountID(ErrorID id) {
158: errorID = id;
159: }
160: }
|