Source code: com/eireneh/util/Reporter.java
1 package com.eireneh.util;
2
3 import com.eireneh.util.event.*;
4
5 /**
6 * This package looks after Exceptions and messages as they happen. It would be
7 * nice not to need this class - the principle being that any library that
8 * encounters an error can throw an exception to indicate that there is a
9 * problem. However this is not always the case. For example:
10 * <li>static class constructors should not throw, unless the class really is
11 * of no use given the error, and yet we may want to tell the user that
12 * there was a (non-critical) error.</li>
13 * <li>Any library routine that works in a loop, applying some (potentially
14 * failing) functionality, may want to continue the work without throwing
15 * in response to a single error.</li>
16 * <li>The class being implemented may implement an interface that disallows
17 * nested exceptions and yet does not want to loose the root cause error
18 * information. (This is the weakest of the above arguements, but probably
19 * still valid.)</li>
20 * However in many of the times this class is used, this is the reason:
21 * <li>Within UI specific code - to throw up a dialog box (or whatever). Now
22 * this use is currently tollerated, however it is probably a poor idea to
23 * use GUI agnostic messaging in a GUI specific context. But I'm not
24 * bothered enough to change it now. Specifically this use is deprecated
25 * because it makes the app more susceptible to the configuration of the
26 * things that listen to reports.</li>
27 *
28 * <table border='1' cellPadding='3' cellSpacing='0' width="100%">
29 * <tr><td bgColor='white'class='TableRowColor'><font size='-7'>
30 * Distribution Licence:<br />
31 * Project B is free software; you can redistribute it
32 * and/or modify it under the terms of the GNU General Public License,
33 * version 2 as published by the Free Software Foundation.<br />
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37 * General Public License for more details.<br />
38 * The License is available on the internet
39 * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, by writing to
40 * <i>Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
41 * MA 02111-1307, USA</i>, Or locally at the Licence link below.<br />
42 * The copyright to this program is held by it's authors.
43 * </font></td></tr></table>
44 * @see <a href='http://www.eireneh.com/servlets/Web'>Project B Home</a>
45 * @see docs.Licence
46 * @author Joe Walker
47 */
48 public class Reporter
49 {
50 /**
51 * Enforce Singleton
52 */
53 private Reporter()
54 {
55 }
56
57 /**
58 * Something has gone wrong. We need to tell the user or someone, but
59 * we can carry on. In general having caught an exception and passed
60 * it to Reporter.informUser(), you should not throw another Exception.
61 * Called to fire a commandEntered event to all the Listeners
62 * @param source The cause of the problem, a Component if possible.
63 * @param ex The Exception that was thrown
64 */
65 public static void informUser(Object source, Throwable prob)
66 {
67 if (prob instanceof ThreadDeath)
68 throw (ThreadDeath) prob;
69
70 // There is a danger here because fireCapture calls informUser
71 // if something goes wrong. It feels dangerous, but is probably ok
72 // The only problem that I can think of is that if there are 2
73 // CaptureListeners with problems then the 2nd will be hit twice.
74 fireCapture(new ReporterEvent(prob));
75 }
76
77 /**
78 * Something has happened. We need to tell the user or someone.
79 *
80 * <p>Maybe we should have an extra parameter (or even several
81 * versions of this method like log*()) that describes the severity
82 * of the message. A Sw*ng listener could use this to decide the
83 * icon in the OptionPane for example.</p>
84 *
85 * @param source The cause of the message, a Component if possible.
86 * @param message The message to pass to the user
87 */
88 public static void informUser(String message)
89 {
90 fireCapture(new ReporterEvent(message));
91 }
92
93 /**
94 * Add an Exception listener to the list of things wanting
95 * to know whenever we capture an Exception
96 */
97 public static void addReporterListener(ReporterListener li)
98 {
99 inform_list.add(ReporterListener.class, li);
100 }
101
102 /**
103 * Remove an Exception listener from the list of things wanting
104 * to know whenever we capture an Exception
105 */
106 public static void removeReporterListener(ReporterListener li)
107 {
108 inform_list.remove(ReporterListener.class, li);
109 }
110
111 /**
112 * Log a message
113 * @param source Where the message comes from
114 * @param message The text message
115 */
116 protected static void fireCapture(ReporterEvent ev)
117 {
118 // Guaranteed to return a non-null array
119 Object[] listeners = inform_list.getListenerList();
120
121 // Process the listeners last to first, notifying
122 // those that are interested in this event
123 for (int i=listeners.length-2; i>=0; i-=2)
124 {
125 if (listeners[i] == ReporterListener.class)
126 {
127 ReporterListener li = (ReporterListener) listeners[i+1];
128 try
129 {
130 if (ev.getException() != null)
131 li.reportException(ev);
132 else
133 li.reportMessage(ev);
134 }
135 catch (Throwable ex)
136 {
137 if (ex instanceof ThreadDeath)
138 throw (ThreadDeath) ex;
139
140 inform_list.remove(CaptureListener.class, li);
141
142 log.log(Level.WARNING, "Dispatch failure", ex);
143 }
144 }
145 }
146 }
147
148 /** The log stream */
149 protected static Logger log = Logger.getLogger("bible.passage");
150
151 /** The list of listeners */
152 protected static EventListenerList inform_list = new EventListenerList();
153 }