KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > ErrorManager


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide;
21
22 import java.io.IOException JavaDoc;
23 import java.io.PrintStream JavaDoc;
24 import java.io.PrintWriter JavaDoc;
25 import java.io.StringWriter JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.Enumeration JavaDoc;
29 import java.util.HashSet JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.ResourceBundle JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.WeakHashMap JavaDoc;
36 import java.util.concurrent.Callable JavaDoc;
37 import java.util.logging.Level JavaDoc;
38 import java.util.logging.LogRecord JavaDoc;
39 import java.util.logging.Logger JavaDoc;
40 import org.openide.util.Enumerations;
41 import org.openide.util.Lookup;
42 import org.openide.util.LookupEvent;
43 import org.openide.util.LookupListener;
44 import org.openide.util.WeakSet;
45
46 /**
47  * A more or less <em>deprecated</em> system of managing, annotating, and classifying errors
48  * and log messages.
49  * <p>
50  * Rather then using the {@link ErrorManager} consider using JDK's {@link Logger}
51  * for reporting log events, unwanted exceptions, etc. The methods
52  * in this class which are deprecated are annotated with a description
53  * how to use use the {@link Logger} methods to achieve the same goal.
54  * </p>
55  * <p>
56  * The levels in descending order are:
57  * <ul>
58  * <li>ERROR (highest value)
59  * <li>EXCEPTION
60  * <li>USER
61  * <li>WARNING
62  * <li>INFORMATIONAL
63  * <li>UNKNOWN (lowest value)
64  * </ul>
65  * </p>
66  *
67  * <div class="nonnormative">
68  * <p>How to...</p>
69  * <dl>
70  *
71  * <dt>Handle an exception</dt>
72  * <dd>
73  * <p>If it might be an important error (show the user):</p>
74  * <pre>
75  * try {
76  * foo.doSomething();
77  * } catch (IOException ioe) {
78  * <!--
79  * Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, "msg", ioe);
80  * // used to be
81  * -->
82  * ErrorManager.getDefault().notify(ioe);
83  * <!--
84  * }
85  * -->
86  * </pre>
87  * <p>If it is not very important but should be sent to the log file:</p>
88  * <pre>
89  * try {
90  * foo.doSomething();
91  * } catch (IOException ioe) {
92  * Logger.getLogger(YourClass.class.getName()).log(Level.CONFIG, "msg", ioe);
93  * // used to be:
94  * // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioe);
95  * }
96  * </pre>
97  * <p>If it is the normal outcome of a user action
98  * and there is no need to show stack traces to the user:</p>
99  * <pre>
100  * try {
101  * foo.doSomething();
102  * } catch (IOException ioe) {
103  * <!--
104  * Logger.getAnonymousLogger().log(Level.INFO, "msg", ioe);
105  * // used to be:
106  * -->
107  * ErrorManager.getDefault().notify(ErrorManager.USER, ioe);
108  * }
109  * </pre>
110  * <p>You can also specify the severity when you are creating the
111  * exception (by annotating it), rather than relying on the notifier
112  * to do this. In that case, if the notifier just use the plain form
113  * of <code>notify</code> (i.e. <code>UNKNOWN</code> severity), the
114  * annotated severity is used.</p>
115  * </dd>
116  *
117  * <dt>Retain nested stacktraces / change exception type</dt>
118  * <dd>
119  * <pre>
120  * public void doSomething() throws IOException {
121  * try {
122  * doSomethingElse();
123  * } catch (IllegalArgumentException iae) {
124  * IOException ioe = new IOException("did not work: " + iae);
125  * ioe.initCause(iae);
126  * // used to be: ErrorManager.getDefault().annotate(ioe, iae);
127  * throw ioe;
128  * }
129  * }
130  * </pre>
131  * <p>You can also just use JDK 1.4 causes:</p>
132  * <pre>
133  * public void doSomething() throws IOException {
134  * try {
135  * doSomethingElse();
136  * } catch (IllegalArgumentException iae) {
137  * IOException ioe = new IOException("did not work: " + iae);
138  * ioe.initCause(iae);
139  * throw ioe;
140  * }
141  * }
142  * // ...
143  * try {
144  * foo.doSomething();
145  * } catch (IOException ioe) {
146  * // The IllegalArgumentException is still available here:
147  * ErrorManager.getDefault().notify(ioe);
148  * // or use logging
149  * Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ioe);
150  * }
151  * </pre>
152  * </dd>
153  *
154  * <dt>Provide a user-visible (localized) message</dt>
155  * <dd>
156  * <pre>
157  * public void doSomething(File f) throws IOException {
158  * if (!f.isFile()) {
159  * IOException e = new IOException("Not a file: " + f); // NOI18N
160  * // For what the user actually sees:
161  * ErrorManager.getDefault().annotate(e,
162  * NbBundle.getMessage(This.class, "EXC_not_a_file", f));
163  * throw e;
164  * }
165  * }
166  * </pre>
167  * <p>You can also add the message when the exception is caught rather
168  * than when it is thrown. You could even have one piece of code throw
169  * an exception, another annotate it, and yet another notify it.
170  * </dd>
171  *
172  * <dt>Collecting several exceptions and wrapping them in one</dt>
173  * <dd>
174  * <pre>
175  * IOException all = null;
176  * for (int i = 0; i < things.length; i++) {
177  * try {
178  * things[i].process();
179  * } catch (ThingProcessingException e) {
180  * if (all == null) {
181  * all = new IOException("Could not process one or more things"); // NOI18N
182  * }
183  * ErrorManager.getDefault().annotate(all, e);
184  * }
185  * }
186  * if (all != null) {
187  * throw all;
188  * }
189  * </pre>
190  * <dd>
191  *
192  * <dt>Logging a warning message just simply uses the JDK's logging API</dt>
193  * <dd>
194  * <pre>
195  * public void doSomething(String arg) {
196  * if (arg.length() == 0) {
197  * Logger.getLogger(YourClass.class.getName()).log(Leverl.WARNING,
198  * "Warning: doSomething called on empty string");
199  * return;
200  * }
201  * // ...
202  * }
203  * </pre>
204  * </dd>
205  *
206  * <dt>Logging messages for some subcomponent can be done easily with JDK's logging API</dt>
207  * <dd>
208  * <pre>
209  * package org.netbeans.modules.foo;
210  * class FooModule {
211  * public static final Logger ERR =
212  * Logger.getLogger("org.netbeans.modules.foo");
213  * }
214  * // ...
215  * class Something {
216  * public void doSomething(String arg) {
217  * LogRecord rec = new LogRecord(Level.FINE, "MSG_Key");
218  * // where in the Bundle.properties one has:
219  * // MSG_Key=Called doSomething with arg {0}
220  * rec.setResourceBundle(NbBundle.getBundle(Something.class));
221  * rec.setParameters(new Object[] { arg });
222  * ERR.log(rec);
223  * }
224  * }
225  * </pre>
226  * </dd>
227  *
228  * </dl>
229  * </div>
230  * @author Jaroslav Tulach, Jesse Glick
231  */

232 public abstract class ErrorManager extends Object JavaDoc {
233     // XXX deprecate error manager after phase II and III are done. See:
234
// http://openide.netbeans.org/tutorial/reviews/opinions_35067.html
235

236     /**
237      * Undefined severity.
238      * May be used only in {@link #notify(int, Throwable)}
239      * and {@link #annotate(Throwable, int, String, String, Throwable, Date)}.
240      */

241     public static final int UNKNOWN = 0x00000000;
242
243     /** Message that would be useful for tracing events but which need not be a problem. */
244     public static final int INFORMATIONAL = 0x00000001;
245
246     /** Something went wrong in the software, but it is continuing and the user need not be bothered. */
247     public static final int WARNING = 0x00000010;
248
249     /** Something the user should be aware of. */
250     public static final int USER = 0x00000100;
251
252     /** Something went wrong, though it can be recovered. */
253     public static final int EXCEPTION = 0x00001000;
254
255     /** Serious problem, application may be crippled. */
256     public static final int ERROR = 0x00010000;
257
258     /** We keep a reference to our proxy ErrorManager here. */
259     private static DelegatingErrorManager current;
260
261     /** Getter for the default version of error manager.
262      * @return the error manager installed in the system
263      * @since 2.1
264      */

265     public static ErrorManager getDefault() {
266         synchronized (ErrorManager.class) {
267             if (current != null) {
268                 return current;
269             }
270         }
271
272         return getDefaultDelegate();
273     }
274
275     private static DelegatingErrorManager getDefaultDelegate() {
276         DelegatingErrorManager c = new DelegatingErrorManager(""); // NOI18N
277

278         try {
279             c.initialize();
280
281             synchronized (ErrorManager.class) {
282                 if (current == null) {
283                     current = c;
284
285                     // r is not null after c.initialize();
286
current.r.addLookupListener(current);
287                 }
288             }
289         } catch (RuntimeException JavaDoc e) {
290             // #20467
291
e.printStackTrace();
292             current = c;
293         } catch (LinkageError JavaDoc e) {
294             // #20467
295
e.printStackTrace();
296             current = c;
297         }
298
299         return current;
300     }
301
302     /** Associates annotations with an exception.
303     *
304     * @param t the exception
305     * @param arr array of annotations (or <code>null</code>)
306     * @return the same exception <code>t</code> (as a convenience)
307     */

308     public abstract Throwable JavaDoc attachAnnotations(Throwable JavaDoc t, Annotation[] arr);
309
310     /** Finds annotations associated with a given exception.
311     * @param t the exception
312     * @return array of annotations or <code>null</code>
313     */

314     public abstract Annotation[] findAnnotations(Throwable JavaDoc t);
315
316     /** Annotates given exception with given values. All the
317     * previous annotations are kept and this new one is added at
318     * the top of the annotation stack (index 0 of the annotation
319     * array).
320     *
321     * @param t the exception
322     * @param severity integer describing severity, e.g. {@link #EXCEPTION}
323     * @param message message to attach to the exception or <code>null</code>
324     * @param localizedMessage localized message for the user or <code>null</code>
325     * @param stackTrace exception representing the stack trace or <code>null</code>
326     * @param date date or <code>null</code>
327     * @return the same exception <code>t</code> (as a convenience)
328     */

329     public abstract Throwable JavaDoc annotate(
330         Throwable JavaDoc t, int severity, String JavaDoc message, String JavaDoc localizedMessage, Throwable JavaDoc stackTrace, java.util.Date JavaDoc date
331     );
332
333     /** Prints the exception to the log file and (possibly) notifies the user.
334      * Use of {@link #UNKNOWN} severity means that the error manager should automatically
335      * select an appropriate severity level, for example based on the contents of
336      * annotations in the throwable.
337     * @param severity the severity to be applied to the exception (overrides default), e.g. {@link #EXCEPTION}
338     * @param t the exception to notify
339     */

340     public abstract void notify(int severity, Throwable JavaDoc t);
341
342     /** Prints the exception to the log file and (possibly) notifies the user.
343      * Guesses at the severity.
344     * @param t the exception to notify
345      * @see #UNKNOWN
346      * @see #notify(int, Throwable)
347     */

348     public final void notify(Throwable JavaDoc t) {
349         notify(UNKNOWN, t);
350     }
351
352     /** Logs the message to a file and (possibly) tells the user.
353     * @param severity the severity to be applied (overrides default)
354     * @param s the log message
355     */

356     public abstract void log(int severity, String JavaDoc s);
357     // not yet: after phase III: * @deprecated use {@link Logger#log}
358

359     /** Logs the message to log file and (possibly) tells the user.
360      * Uses a default severity.
361     * @param s the log message
362     */

363     public final void log(String JavaDoc s) {
364     // not yet: after phase III: * @deprecated {@link Logger#log}
365
log(INFORMATIONAL, s);
366     }
367
368     /** Test whether a messages with given severity will be logged in advance.
369      * Can be used to avoid the construction of complicated and expensive
370      * logging messages.
371      * <p>The default implementation just returns true. Subclasses
372      * should override to be more precise - <strong>treat this method as abstract</strong>.
373      * @param severity the severity to check, e.g. {@link #EXCEPTION}
374      * @return <code>false</code> if the next call to {@link #log(int,String)} with this severity will
375      * discard the message
376      */

377     public boolean isLoggable(int severity) {
378      // not yet: after phase III: * @deprecated Use {@link Logger#isLoggable}
379
return true;
380     }
381
382     /**
383      * Test whether a throwable, if {@link #notify(int, Throwable) notified} at the given
384      * level, will actually be displayed in any way (even to a log file etc.).
385      * If not, there is no point in constructing it.
386      * <p>This method is distinct from {@link #isLoggable} because an error manager
387      * implementation may choose to notify stack traces at a level where it would
388      * not log messages. See issue #24056 for justification.
389      * <p>The default implementation just calls {@link #isLoggable}. Subclasses
390      * should override to be more precise - <strong>treat this method as abstract</strong>.
391      * @param severity a notification severity
392      * @return true if a throwable notified at this severity will be used; false if it will be ignored
393      * @since 3.18
394      */

395     public boolean isNotifiable(int severity) {
396         return isLoggable(severity);
397     }
398
399     /** Returns an instance with given name.
400      * <p>By convention, you can name error managers the same as packages (or classes)
401      * they are designed to report information from.
402      * For example, <code>org.netbeans.modules.mymodule.ComplicatedParser</code>.
403      * <p>The error manager implementation should provide some way of configuring e.g.
404      * the logging level for error managers of different names. For example, in the basic
405      * NetBeans core implementation, you can define a system property with the same name
406      * as the future error manager (or a package prefix of it) whose value is the numeric
407      * logging level (e.g. <samp>-J-Dorg.netbeans.modules.mymodule.ComplicatedParser=0</samp>
408      * to log everything). Other implementations may have quite different ways of configuring
409      * the error managers.
410      * @param name the desired identifying name
411      * @return a new error manager keyed off of that name
412      */

413     public abstract ErrorManager getInstance(String JavaDoc name);
414
415     //
416
// Helper methods
417
//
418

419     /** Annotates given exception with given values. All the
420     * previous annotations are kept and this new is added at
421     * the top of the annotation stack (index 0 of the annotation
422     * array).
423     *
424     * @param t the exception
425     * @param localizedMessage localized message for the user or null
426     * @return the same exception <code>t</code> (as a convenience)
427     */

428     public final Throwable JavaDoc annotate(Throwable JavaDoc t, String JavaDoc localizedMessage) {
429         return annotate(t, UNKNOWN, null, localizedMessage, null, null);
430     }
431
432     /** Annotates target exception with given exception. All the
433     * previous annotations are kept and this new is added at
434     * the top of the annotation stack (index 0 of the annotation
435     * array).
436      * <p>Consider using {@link Throwable#initCause} instead; this
437      * will be correctly reported by the NetBeans error manager, and
438      * also works properly with {@link Throwable#printStackTrace()}.
439     * @param target the exception to be annotated
440     * @param t the exception that will be added
441     * @return the same exception <code>target</code> (as a convenience)
442     */

443     public final Throwable JavaDoc annotate(Throwable JavaDoc target, Throwable JavaDoc t) {
444         return annotate(target, UNKNOWN, null, null, t, null);
445     }
446
447     /** Takes annotations from one exception and associates
448     * them with another one.
449     *
450     * @param t the exception to annotate
451     * @param copyFrom exception to take annotations from
452     * @return the same exception <code>t</code> (as a convenience)
453     * @deprecated Now does the same thing as {@link #annotate(Throwable,Throwable)}
454     * except marks the annotation {@link #UNKNOWN} severity. Otherwise
455     * you used to have inadvertent data loss when <code>copyFrom</code>
456     * had annotations of its own: the subannotations were kept but the
457     * main stack trace in <code>copyFrom</code> was discarded. In practice
458     * you usually want to keep all of <code>copyFrom</code>; if for some
459     * reason you just want to keep annotations, please do so explicitly
460     * using {@link #findAnnotations} and {@link #attachAnnotations}.
461     */

462     @Deprecated JavaDoc
463     public final Throwable JavaDoc copyAnnotation(Throwable JavaDoc t, Throwable JavaDoc copyFrom) {
464         // Cf. #17874 for the change in behavior.
465

466         /*
467         Annotation[] arr = findAnnotations (copyFrom);
468
469         if (arr != null) {
470             return attachAnnotations (
471                        t, arr
472                    );
473         } else {
474         */

475         return annotate(t, UNKNOWN, null, null, copyFrom, null);
476
477         /*
478         }
479         */

480     }
481
482     /** Annotation that can be attached to an error.
483     */

484     public static interface Annotation {
485         /** Non-localized message.
486         * @return associated message or <code>null</code>
487         */

488         public abstract String JavaDoc getMessage();
489
490         /** Localized message.
491         * @return message to be presented to the user or <code>null</code>
492         */

493         public abstract String JavaDoc getLocalizedMessage();
494
495         /** Stack trace. The stack trace should locate the method
496         * and position in the method where the error occurred.
497         *
498         * @return exception representing the location of the error or <code>null</code>
499         */

500         public abstract Throwable JavaDoc getStackTrace();
501
502         /** Time at which the exception occurred.
503         * @return the time or <code>null</code>
504         */

505         public abstract java.util.Date JavaDoc getDate();
506
507         /** Severity of the exception.
508          * {@link #UNKNOWN} serves as the default.
509         * @return number representing the severity, e.g. {@link ErrorManager#EXCEPTION}
510         */

511         public abstract int getSeverity();
512     }
513      // end of Annotation
514

515     /**
516      * Implementation of ErrorManager that delegates to the ones found by
517      * lookup.
518      */

519     private static class DelegatingErrorManager extends ErrorManager implements LookupListener {
520         private String JavaDoc name = null;
521
522         /**
523          * The set of instances we delegate to. Elements type is ErrorManager.
524          */

525         private Set JavaDoc delegates = new HashSet JavaDoc();
526         
527         /** fallback logger to send messages to */
528         private Logger JavaDoc logger;
529
530         /**
531          * A set that has to be updated when the list of delegates
532          * changes. All instances created by getInstance are held here.
533          */

534         private WeakSet<DelegatingErrorManager> createdByMe = new WeakSet<DelegatingErrorManager>();
535
536         /** If we are the "central" delagate this is not null and
537          * we listen on the result. On newly created delegates this
538          * is null.
539          */

540         Lookup.Result<ErrorManager> r;
541
542         public DelegatingErrorManager(String JavaDoc name) {
543             this.name = name;
544         }
545         
546         /** Initializes the logger.
547          */

548         Logger JavaDoc logger() {
549             if (logger == null) {
550                 logger = Logger.getLogger(this.name);
551             }
552             return logger;
553         }
554
555         /** If the name is not empty creates new instance of
556          * DelegatingErrorManager. Adds it to createdByMe.
557          */

558         public ErrorManager getInstance(String JavaDoc name) {
559             if ((name == null) || ("".equals(name))) { // NOI18N
560

561                 return this;
562             }
563
564             DelegatingErrorManager dem = new DelegatingErrorManager(name);
565
566             synchronized (this) {
567                 attachNewDelegates(dem, name);
568                 createdByMe.add(dem);
569             }
570
571             return dem;
572         }
573
574         /** Calls all delegates. */
575         public Throwable JavaDoc attachAnnotations(Throwable JavaDoc t, Annotation[] arr) {
576             for (Iterator JavaDoc i = delegates.iterator(); i.hasNext();) {
577                 ErrorManager em = (ErrorManager) i.next();
578                 em.attachAnnotations(t, arr);
579             }
580
581             return t;
582         }
583
584         /** Calls all delegates. */
585         public Annotation[] findAnnotations(Throwable JavaDoc t) {
586             for (Iterator JavaDoc i = delegates.iterator(); i.hasNext();) {
587                 ErrorManager em = (ErrorManager) i.next();
588                 Annotation[] res = em.findAnnotations(t);
589
590                 if ((res != null) && (res.length > 0)) {
591                     return res;
592                 }
593             }
594
595             return new Annotation[0];
596         }
597
598         /** Calls all delegates. */
599         public Throwable JavaDoc annotate(
600             Throwable JavaDoc t, int severity, String JavaDoc message, final String JavaDoc localizedMessage, Throwable JavaDoc stackTrace,
601             java.util.Date JavaDoc date
602         ) {
603             if (delegates.isEmpty()) {
604                 LogRecord JavaDoc rec = new LogRecord JavaDoc(convertSeverity(severity, true, Level.ALL), message);
605                 if (stackTrace != null) {
606                     rec.setThrown(stackTrace);
607                 }
608                 if (date != null) {
609                     rec.setMillis(date.getTime());
610                 }
611                 if (localizedMessage != null) {
612                     ResourceBundle JavaDoc rb = new ResourceBundle JavaDoc() {
613                         public Object JavaDoc handleGetObject(String JavaDoc key) {
614                             if ("msg".equals(key)) { // NOI18N
615
return localizedMessage;
616                             } else {
617                                 return null;
618                             }
619                         }
620                         
621                         public Enumeration JavaDoc<String JavaDoc> getKeys() {
622                             return Enumerations.singleton("msg"); // NOI18N
623
}
624                     };
625                     rec.setResourceBundle(rb);
626                     rec.setMessage("msg"); // NOI18N
627
}
628                 
629                 AnnException ann = AnnException.findOrCreate(t, true);
630                 ann.addRecord(rec);
631                 
632                 return t;
633             }
634             
635             for (Iterator JavaDoc i = delegates.iterator(); i.hasNext();) {
636                 ErrorManager em = (ErrorManager) i.next();
637                 em.annotate(t, severity, message, localizedMessage, stackTrace, date);
638             }
639
640             return t;
641         }
642
643         /** Calls all delegates. */
644         public void notify(int severity, Throwable JavaDoc t) {
645             if (delegates.isEmpty()) {
646                 if (enterLogger()) return;
647                 try {
648                     AnnException ext = AnnException.extras.get(t);
649                     if (ext != null) {
650                         t = ext;
651                     }
652                     logger().log(convertSeverity(severity, true, OwnLevel.UNKNOWN), t.getMessage(), t);
653                 } finally {
654                     exitLogger();
655                 }
656                 return;
657             }
658
659             try {
660                 for (Iterator JavaDoc i = delegates.iterator(); i.hasNext();) {
661                     ErrorManager em = (ErrorManager) i.next();
662                     em.notify(severity, t);
663                 }
664             } catch (RuntimeException JavaDoc e) {
665                 // #20467
666
e.printStackTrace();
667                 t.printStackTrace();
668             } catch (LinkageError JavaDoc e) {
669                 // #20467
670
e.printStackTrace();
671                 t.printStackTrace();
672             }
673         }
674
675         /** Calls all delegates. */
676         public void log(int severity, String JavaDoc s) {
677             if (severity == UNKNOWN) {
678                 throw new IllegalArgumentException JavaDoc("ErrorManager.log(UNKNOWN, ...) is not permitted"); // NOI18N
679
}
680
681             if (delegates.isEmpty()) {
682                 Level JavaDoc sev = convertSeverity(severity, false, Level.FINE);
683                 if (enterLogger()) return;
684                 try {
685                     logger().log(sev, s);
686                 } finally {
687                     exitLogger();
688                 }
689                 return;
690             }
691
692             for (Iterator JavaDoc i = delegates.iterator(); i.hasNext();) {
693                 ErrorManager em = (ErrorManager) i.next();
694                 em.log(severity, s);
695             }
696         }
697
698         private static Level JavaDoc convertSeverity(final int severity, boolean forException, Level JavaDoc def) {
699             Level JavaDoc sev = def;
700
701             if (severity >= ERROR) {
702                 sev = Level.SEVERE;
703             } else if (severity >= EXCEPTION) {
704                 sev = Level.SEVERE;
705             } else if (severity >= USER) {
706                 sev = OwnLevel.USER;
707             } else if (severity >= WARNING) {
708                 sev = Level.WARNING;
709             } else if (severity >= INFORMATIONAL) {
710                 sev = forException ? Level.INFO: Level.FINE;
711             }
712             return sev;
713         }
714
715         /** Calls all delegates. */
716         public boolean isLoggable(int severity) {
717             if (severity == UNKNOWN) {
718                 throw new IllegalArgumentException JavaDoc("ErrorManager.isLoggable(UNKNOWN) is not permitted"); // NOI18N
719
}
720
721             if (delegates.isEmpty()) {
722                 return logger().isLoggable(convertSeverity(severity, false, null));
723             }
724
725             for (Iterator JavaDoc i = delegates.iterator(); i.hasNext();) {
726                 ErrorManager em = (ErrorManager) i.next();
727
728                 if (em.isLoggable(severity)) {
729                     return true;
730                 }
731             }
732
733             return false;
734         }
735
736         /** Calls all delegates. */
737         public boolean isNotifiable(int severity) {
738             if (severity == UNKNOWN) {
739                 throw new IllegalArgumentException JavaDoc("ErrorManager.isNotifiable(UNKNOWN) is not permitted"); // NOI18N
740
}
741
742             if (delegates.isEmpty()) {
743                 return logger().isLoggable(convertSeverity(severity, true, null));
744             }
745
746             for (Iterator JavaDoc i = delegates.iterator(); i.hasNext();) {
747                 ErrorManager em = (ErrorManager) i.next();
748
749                 if (em.isNotifiable(severity)) {
750                     return true;
751                 }
752             }
753
754             return false;
755         }
756
757         /**
758          * Updates the list of delegates. Also updates all instances created
759          * by ourselves.
760          */

761         public synchronized void setDelegates(Collection JavaDoc<? extends ErrorManager> newDelegates) {
762             java.util.LinkedHashSet JavaDoc<ErrorManager> d;
763             d = new java.util.LinkedHashSet JavaDoc<ErrorManager>(newDelegates);
764             delegates = d;
765
766             for (Iterator JavaDoc i = createdByMe.iterator(); i.hasNext();) {
767                 DelegatingErrorManager dem = (DelegatingErrorManager) i.next();
768                 attachNewDelegates(dem, dem.getName());
769             }
770         }
771
772         private String JavaDoc getName() {
773             return name;
774         }
775
776         /**
777          * Takes all our delegates, asks them for an instance identified by
778          * name and adds those results as new delegates for dem.
779          * @param String name
780          * @param DelagatingErrorManager d the instance to which we will attach
781          */

782         private void attachNewDelegates(DelegatingErrorManager dem, String JavaDoc name) {
783             Set JavaDoc<ErrorManager> newDelegatesForDem = new HashSet JavaDoc<ErrorManager>();
784
785             for (Iterator JavaDoc j = delegates.iterator(); j.hasNext();) {
786                 ErrorManager e = (ErrorManager) j.next();
787                 newDelegatesForDem.add(e.getInstance(name));
788             }
789
790             dem.setDelegates(newDelegatesForDem);
791         }
792
793         /** Blocks on lookup and after the lookup returns updates
794          * delegates and adds a listener.
795          */

796         public void initialize() {
797             r = Lookup.getDefault().lookup(new Lookup.Template<ErrorManager>(ErrorManager.class));
798             setDelegates(r.allInstances());
799         }
800
801         /** Updates the delegates.*/
802         public void resultChanged(LookupEvent ev) {
803             if (r != null) {
804                 setDelegates(r.allInstances());
805             }
806         }
807
808         private static volatile Thread JavaDoc lastThread;
809         private static boolean enterLogger() {
810             if (lastThread == Thread.currentThread()) {
811                 new Exception JavaDoc("using error manager from inside a logger").printStackTrace(); // NOI18N
812
return true;
813             }
814             lastThread = Thread.currentThread();
815             return false;
816         }
817
818         private static void exitLogger() {
819             lastThread = null;
820         }
821     }
822     
823     /** An exception that has a log record associated with itself, so
824      * the NbErrorManager can extract info about the annotation.
825      */

826     private static final class AnnException extends Exception JavaDoc implements Callable JavaDoc<LogRecord JavaDoc[]> {
827         private List JavaDoc<LogRecord JavaDoc> records;
828         /** additional mapping from throwables that refuse initCause call */
829         private static Map JavaDoc<Throwable JavaDoc, AnnException> extras = new WeakHashMap JavaDoc<Throwable JavaDoc, AnnException>();
830
831         public String JavaDoc getMessage() {
832             StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
833             String JavaDoc sep = "";
834             for (LogRecord JavaDoc r : records) {
835                 if (r.getMessage() != null) {
836                     sb.append(sep);
837                     sb.append(r.getMessage());
838                     sep = "\n";
839                 }
840             }
841             return sb.toString();
842         }
843
844         static AnnException findOrCreate(Throwable JavaDoc t, boolean create) {
845             if (t instanceof AnnException) {
846                 return (AnnException)t;
847             }
848             if (t.getCause() == null) {
849                 if (create) {
850                     try {
851                         t.initCause(new AnnException());
852                     } catch (IllegalStateException JavaDoc x) {
853                         AnnException ann = extras.get(t);
854                         if (ann == null) {
855                             ann = new AnnException();
856                             ann.initCause(t);
857                             Logger.getLogger(ErrorManager.class.getName()).log(Level.FINE, "getCause was null yet initCause failed for " + t, x);
858                             extras.put(t, ann);
859                         }
860                         return ann;
861                     }
862                 }
863                 return (AnnException)t.getCause();
864             }
865             return findOrCreate(t.getCause(), create);
866         }
867
868         private AnnException() {
869         }
870
871         public synchronized void addRecord(LogRecord JavaDoc rec) {
872             if (records == null) {
873                 records = new ArrayList JavaDoc<LogRecord JavaDoc>();
874             }
875             records.add(rec);
876         }
877
878         public LogRecord JavaDoc[] call() {
879             List JavaDoc<LogRecord JavaDoc> r = records;
880             LogRecord JavaDoc[] empty = new LogRecord JavaDoc[0];
881             return r == null ? empty : r.toArray(empty);
882         }
883
884         public void printStackTrace(PrintStream JavaDoc s) {
885             super.printStackTrace(s);
886             logRecords(s);
887         }
888
889         public void printStackTrace(PrintWriter JavaDoc s) {
890             super.printStackTrace(s);
891             logRecords(s);
892         }
893
894         public void printStackTrace() {
895             printStackTrace(System.err);
896         }
897
898         private void logRecords(Appendable JavaDoc a) {
899             List JavaDoc<LogRecord JavaDoc> r = records;
900             if (r == null) {
901                 return;
902             }
903             try {
904
905                 for (LogRecord JavaDoc log : r) {
906                     if (log.getMessage() != null) {
907                         a.append(log.getMessage()).append("\n");;
908                     }
909                     if (log.getThrown() != null) {
910                         StringWriter JavaDoc w = new StringWriter JavaDoc();
911                         log.getThrown().printStackTrace(new PrintWriter JavaDoc(w));
912                         a.append(w.toString()).append("\n");
913                     }
914                 }
915             } catch (IOException JavaDoc ex) {
916                 ex.printStackTrace();
917             }
918         }
919     } // end AnnException
920

921     private static final class OwnLevel extends Level JavaDoc {
922         public static final Level JavaDoc USER = new OwnLevel("USER", 1973); // NOI18N
923
public static final Level JavaDoc UNKNOWN = new OwnLevel("SEVERE", Level.SEVERE.intValue() + 1); // NOI18N
924

925         private OwnLevel(String JavaDoc s, int i) {
926             super(s, i);
927         }
928     } // end of UserLevel
929
}
930
Popular Tags