Lines 1-11
Link Here
|
1 |
/* |
1 |
/* |
2 |
* Sun Public License Notice |
2 |
* Sun Public License Notice |
3 |
* |
3 |
* |
4 |
* The contents of this file are subject to the Sun Public License |
4 |
* The contents of this file are subject to the Sun Public License |
5 |
* Version 1.0 (the "License"). You may not use this file except in |
5 |
* Version 1.0 (the "License"). You may not use this file except in |
6 |
* compliance with the License. A copy of the License is available at |
6 |
* compliance with the License. A copy of the License is available at |
7 |
* http://www.sun.com/ |
7 |
* http://www.sun.com/ |
8 |
* |
8 |
* |
9 |
* The Original Code is NetBeans. The Initial Developer of the Original |
9 |
* The Original Code is NetBeans. The Initial Developer of the Original |
10 |
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun |
10 |
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun |
11 |
* Microsystems, Inc. All Rights Reserved. |
11 |
* Microsystems, Inc. All Rights Reserved. |
Lines 31-373
Link Here
|
31 |
import java.util.Locale; |
31 |
import java.util.Locale; |
32 |
import java.util.Map; |
32 |
import java.util.Map; |
33 |
import java.util.MissingResourceException; |
33 |
import java.util.MissingResourceException; |
|
|
34 |
import java.util.ResourceBundle; |
34 |
import java.util.Set; |
35 |
import java.util.Set; |
35 |
import java.util.StringTokenizer; |
36 |
import java.util.StringTokenizer; |
36 |
import java.util.WeakHashMap; |
37 |
import java.util.WeakHashMap; |
|
|
38 |
import java.util.concurrent.Callable; |
39 |
import java.util.logging.Handler; |
37 |
import java.util.logging.Level; |
40 |
import java.util.logging.Level; |
38 |
import java.util.logging.LogRecord; |
41 |
import java.util.logging.LogRecord; |
39 |
import java.util.logging.Logger; |
42 |
import java.util.logging.Logger; |
40 |
import org.openide.ErrorManager; |
43 |
import org.openide.ErrorManager; |
|
|
44 |
import org.openide.util.Lookup; |
41 |
import org.openide.util.NbBundle; |
45 |
import org.openide.util.NbBundle; |
42 |
import org.xml.sax.SAXParseException; |
46 |
import org.xml.sax.SAXParseException; |
43 |
|
47 |
|
44 |
/** Wraps errormanager with logger. |
48 |
/** Wraps errormanager with logger. |
45 |
* |
49 |
* |
46 |
* @author Jaroslav Tulach, Jesse Glick |
50 |
* @author Jaroslav Tulach, Jesse Glick |
47 |
*/ |
51 |
*/ |
48 |
public final class NbErrorManager extends ErrorManager { |
52 |
public final class NbErrorManager extends Handler { |
49 |
static { |
53 |
/** our root logger */ |
50 |
System.setProperty("sun.awt.exception.handler", "org.netbeans.core.NbErrorManager$AWTHandler"); // NOI18N |
54 |
static NbErrorManager ROOT = new NbErrorManager(); |
51 |
} |
55 |
|
52 |
|
56 |
Exc createExc(Throwable t, Level severity, LogRecord add) { |
53 |
/** logger to delegate to */ |
57 |
LogRecord[] ann = findAnnotations(t, add); |
54 |
private Logger logger; |
58 |
return new Exc(t, severity, ann, findAnnotations0(t, add, true, new HashSet())); |
55 |
/** mapping of Throwables to errors */ |
|
|
56 |
private static Map<Throwable,List<Annotation>> map = new HashMap<Throwable,List<Annotation>>(); |
57 |
|
58 |
public NbErrorManager() { |
59 |
this(""); |
60 |
} |
59 |
} |
61 |
|
60 |
|
62 |
private NbErrorManager(String pfx) { |
61 |
public void publish(LogRecord record) { |
63 |
this(Logger.getLogger(pfx)); |
62 |
if (record.getThrown() != null) { |
|
|
63 |
Level level = record.getLevel(); |
64 |
if (level.intValue() == Level.WARNING.intValue() + 1) { |
65 |
// unknown level |
66 |
level = null; |
67 |
} |
68 |
Exc ex = createExc(record.getThrown(), level, record.getLevel().intValue() == 1973 ? record : null); |
69 |
NotifyException.notify(ex); |
70 |
} |
64 |
} |
71 |
} |
65 |
|
72 |
|
66 |
/** |
73 |
public void flush() { |
67 |
* Construct for testing. |
74 |
//logWriter.flush(); |
68 |
* @see "#18141" |
|
|
69 |
*/ |
70 |
NbErrorManager(Logger l) { |
71 |
this.logger = l; |
72 |
} |
75 |
} |
73 |
|
76 |
|
74 |
private static Level mapSeverity (int severity, boolean forException) { |
77 |
public void close() throws SecurityException { |
75 |
Level sev = Level.SEVERE; |
78 |
// nothing needed |
76 |
|
|
|
77 |
if (severity >= ERROR) { |
78 |
sev = Level.SEVERE; |
79 |
} else if (severity >= EXCEPTION) { |
80 |
sev = Level.SEVERE; |
81 |
} else if (severity >= USER) { |
82 |
sev = Level.INFO; |
83 |
} else if (severity >= WARNING) { |
84 |
sev = Level.WARNING; |
85 |
} else if (severity >= INFORMATIONAL) { |
86 |
sev = forException ? Level.INFO: Level.FINE; |
87 |
} |
88 |
return sev; |
89 |
} |
90 |
|
91 |
|
92 |
public synchronized Throwable annotate ( |
93 |
Throwable t, |
94 |
int severity, String message, String localizedMessage, |
95 |
Throwable stackTrace, Date date |
96 |
) { |
97 |
List<Annotation> o = map.get (t); |
98 |
|
99 |
List<Annotation> ll; |
100 |
if (o == null) { |
101 |
ll = new ArrayList<Annotation> (); |
102 |
map.put (t, ll); |
103 |
} else { |
104 |
ll = o; |
105 |
} |
106 |
|
107 |
ll.add(0, |
108 |
new Ann (severity, message, localizedMessage, stackTrace, date) |
109 |
); |
110 |
|
111 |
return t; |
112 |
} |
79 |
} |
113 |
|
80 |
|
114 |
|
81 |
/** Extracts localized message from a LogRecord */ |
115 |
/** Associates annotations with this thread. |
82 |
static final String getLocalizedMessage(LogRecord rec) { |
116 |
* |
83 |
ResourceBundle rb = rec.getResourceBundle(); |
117 |
* @param arr array of annotations (or null) |
84 |
if (rb == null) { |
118 |
*/ |
85 |
return null; |
119 |
public synchronized Throwable attachAnnotations (Throwable t, Annotation[] arr) { |
|
|
120 |
List<Annotation> o = map.get (t); |
121 |
List<Annotation> l; |
122 |
if (o == null) { |
123 |
l = new ArrayList<Annotation>(arr.length + 5); |
124 |
map.put (t, l); |
125 |
} else { |
126 |
l = o; |
127 |
} |
86 |
} |
128 |
l.addAll(0, Arrays.asList(arr)); |
|
|
129 |
|
87 |
|
130 |
return t; |
88 |
String msg = rec.getMessage(); |
131 |
} |
89 |
if (msg == null) { |
132 |
|
90 |
return null; |
133 |
/** Honor configured min-severity levels, more or less. |
|
|
134 |
* Actually bump up the effective severity of an exception by one. |
135 |
* Thus by default INFORMATIONAL stack traces are displayed, but not |
136 |
* messages. By playing with min log severity levels, you can get |
137 |
* both, or neither. |
138 |
* @see "#24056" |
139 |
*/ |
140 |
public boolean isNotifiable(int severity) { |
141 |
return logger.isLoggable(mapSeverity(severity, true)); |
142 |
} |
143 |
|
144 |
/** Notifies all the exceptions associated with |
145 |
* this thread. |
146 |
*/ |
147 |
public synchronized void notify (int severity, Throwable t) { |
148 |
// synchronized to ensure that only one exception is |
149 |
// written to the thread |
150 |
|
151 |
Exc ex = createExc(t, severity); |
152 |
|
153 |
if (!isNotifiable(ex.getSeverity())) { |
154 |
return; |
155 |
} |
156 |
|
157 |
//issue 36878 - printing the stack trace on a user error is |
158 |
//disconcerting because it makes it look like something went wrong |
159 |
//with the software. |
160 |
|
161 |
//Note the algorithm below is different than that of Exc.getSeverity() - |
162 |
//there are cases (e.g. a property editor over a filesystem) where |
163 |
//an exception may be annotated as severe, but in the context |
164 |
//it is not - thus we check if *any* annotation is USER, rather than |
165 |
//that the highest level severity in the annotation is USER |
166 |
boolean wantStackTrace = severity != USER; |
167 |
if (wantStackTrace) { |
168 |
Annotation[] ann = findAnnotations(t); |
169 |
if (ann != null) { |
170 |
for (int i=0; i < ann.length; i++) { |
171 |
if (ann[i] instanceof Ann) { |
172 |
if (((Ann) ann[i]).getSeverity() == USER) { |
173 |
wantStackTrace = false; |
174 |
break; |
175 |
} |
176 |
} |
177 |
} |
178 |
} |
179 |
} |
91 |
} |
180 |
if (wantStackTrace) { |
92 |
|
181 |
String s = ex.getSeverity() == ErrorManager.INFORMATIONAL ? "INFORMATIONAL" : ""; // NOI18N |
93 |
String format = rb.getString(msg); |
182 |
Level level = mapSeverity(ex.getSeverity(), true); |
|
|
183 |
LogRecord rec = new LogRecord(level, "MSG_ExceptionHeader"); // NOI18N |
184 |
rec.setResourceBundle(NbBundle.getBundle(NbErrorManager.class)); |
185 |
rec.setMillis(ex.getDate().getTime()); |
186 |
rec.setParameters(new Object[] { s, ex.getDate() }); |
187 |
try { |
188 |
if (!enterLog()) { |
189 |
logger.log(rec); |
190 |
} |
191 |
} finally { |
192 |
exitLog(); |
193 |
} |
194 |
|
195 |
StringWriter annotate = new StringWriter(); |
196 |
PrintWriter pw = new PrintWriter(annotate); |
197 |
ex.printStackTrace(pw); |
198 |
pw.close(); |
199 |
|
94 |
|
200 |
try { |
95 |
Object[] arr = rec.getParameters(); |
201 |
if (!enterLog()) { |
96 |
if (arr == null) { |
202 |
logger.log(level, annotate.toString()); |
97 |
return format; |
203 |
} |
|
|
204 |
} finally { |
205 |
exitLog(); |
206 |
} |
207 |
} |
98 |
} |
208 |
|
99 |
|
209 |
if (ex.getSeverity () > INFORMATIONAL) { |
100 |
return MessageFormat.format(format, arr); |
210 |
NotifyException.notify (ex); |
|
|
211 |
} |
212 |
} |
213 |
|
214 |
/** |
215 |
* Just create the exception information for a throwable being notified. |
216 |
* Useful for the unit test. |
217 |
*/ |
218 |
Exc createExc(Throwable t, int severity) { |
219 |
Annotation[] ann = findAnnotations (t); |
220 |
return new Exc (t, severity, ann, findAnnotations0(t, true, new HashSet<Throwable>())); |
221 |
} |
101 |
} |
222 |
|
102 |
|
223 |
public void log(int severity, String s) { |
103 |
/** Finds annotations associated with given exception. |
224 |
try { |
104 |
* @param t the exception |
225 |
if (!enterLog()) { |
105 |
* @return array of annotations or null |
226 |
logger.log(mapSeverity(severity, false), s); |
|
|
227 |
} |
228 |
} finally { |
229 |
exitLog(); |
230 |
} |
231 |
} |
232 |
|
233 |
/** Allows to test whether messages with given severity will be logged |
234 |
* or not prior to constraction of complicated and time expensive |
235 |
* logging messages. |
236 |
* |
237 |
* @param severity the severity to check |
238 |
* @return false if the next call to log method with the same severity will |
239 |
* discard the message |
240 |
*/ |
106 |
*/ |
241 |
public boolean isLoggable (int severity) { |
107 |
public synchronized LogRecord[] findAnnotations(Throwable t, LogRecord add) { |
242 |
return logger.isLoggable(mapSeverity(severity, false)); |
108 |
return findAnnotations0(t, add, false, new HashSet()); |
243 |
} |
109 |
} |
244 |
|
110 |
|
245 |
|
|
|
246 |
/** Returns an instance with given name. The name |
247 |
* can be dot separated list of names creating |
248 |
* a hierarchy. |
249 |
*/ |
250 |
public final ErrorManager getInstance(String name) { |
251 |
String pfx = logger.getName(); |
252 |
if (pfx.length() > 0 && !pfx.endsWith(".")) { |
253 |
pfx += "."; |
254 |
} |
255 |
pfx += name; |
256 |
return new NbErrorManager(pfx); |
257 |
} |
258 |
|
259 |
/** Method (or field) names in various exception classes which give |
260 |
* a nested exception. Fields should be public, methods public no-arg. |
261 |
* Field names should be prefixed with a dot. |
262 |
*/ |
263 |
private static Map<String,String> NESTS = null; |
264 |
private static Throwable extractNestedThrowable(Throwable t) { |
265 |
synchronized (NbErrorManager.class) { |
266 |
if (NESTS == null) { |
267 |
NESTS = new HashMap<String,String>(); |
268 |
NESTS.put("javax.xml.parsers.FactoryConfigurationError", "getException"); // NOI18N |
269 |
NESTS.put("javax.xml.transform.TransformerFactoryConfigurationError", "getException"); // NOI18N |
270 |
NESTS.put("org.xml.sax.SAXException", "getException"); // NOI18N |
271 |
} |
272 |
} |
273 |
for (Class c = t.getClass(); c != Object.class; c = c.getSuperclass()) { |
274 |
String getter = (String)NESTS.get(c.getName()); |
275 |
if (getter != null) { |
276 |
try { |
277 |
if (getter.charAt(0) == '.') { // NOI18N |
278 |
Field f = c.getField(getter.substring(1)); |
279 |
return (Throwable)f.get(t); |
280 |
} else { |
281 |
Method m = c.getMethod(getter); |
282 |
return (Throwable)m.invoke(t); |
283 |
} |
284 |
} catch (Exception e) { |
285 |
// Should not happen. |
286 |
System.err.println("From throwable class: " + c.getName()); // NOI18N |
287 |
e.printStackTrace(); |
288 |
} |
289 |
} |
290 |
} |
291 |
return null; |
292 |
} |
293 |
|
294 |
/** Finds annotations associated with given exception. |
295 |
* @param t the exception |
296 |
* @return array of annotations or null |
297 |
*/ |
298 |
public synchronized Annotation[] findAnnotations (Throwable t) { |
299 |
return findAnnotations0(t, false, new HashSet<Throwable>()); |
300 |
} |
301 |
|
302 |
/** If recursively is true it is not adviced to print all annotations |
111 |
/** If recursively is true it is not adviced to print all annotations |
303 |
* because a lot of warnings will be printed. But while searching for |
112 |
* because a lot of warnings will be printed. But while searching for |
304 |
* localized message we should scan all the annotations (even recursively). |
113 |
* localized message we should scan all the annotations (even recursively). |
305 |
*/ |
114 |
*/ |
306 |
private synchronized Annotation[] findAnnotations0(Throwable t, boolean recursively, Set<Throwable> alreadyVisited) { |
115 |
private synchronized LogRecord[] findAnnotations0(Throwable t, LogRecord add, boolean recursively, Set alreadyVisited) { |
307 |
List<ErrorManager.Annotation> l = map.get (t); |
116 |
List l = new ArrayList(); |
308 |
// MissingResourceException should be printed nicely... --jglick |
117 |
Throwable collect = t; |
309 |
if (t instanceof MissingResourceException) { |
118 |
while (collect != null) { |
310 |
if (l == null) { |
119 |
if (collect instanceof Callable) { |
311 |
l = new ArrayList<ErrorManager.Annotation>(1); |
120 |
Object res = null; |
312 |
} else { |
121 |
try { |
313 |
// make a copy, do not modify it |
122 |
res = ((Callable) collect).call(); |
314 |
l = new ArrayList<ErrorManager.Annotation>(l); |
123 |
} catch (Exception ex) { |
315 |
} |
124 |
ex.printStackTrace(); |
316 |
MissingResourceException mre = (MissingResourceException) t; |
|
|
317 |
String cn = mre.getClassName (); |
318 |
if (cn != null) { |
319 |
l.add (new Ann (EXCEPTION, NbBundle.getMessage (NbErrorManager.class, "EXC_MissingResourceException_class_name", cn), null, null, null)); |
320 |
} |
321 |
String k = mre.getKey (); |
322 |
if (k != null) { |
323 |
l.add (new Ann (EXCEPTION, NbBundle.getMessage (NbErrorManager.class, "EXC_MissingResourceException_key", k), null, null, null)); |
324 |
} |
325 |
if (l.size () == 0) l = null; // not clear if null means something other than new Annotation[0] |
326 |
} else { |
327 |
// #15611: find all kinds of nested exceptions and deal with them too. |
328 |
// Use of Throwable.initCause is preferred. |
329 |
Throwable t2 = extractNestedThrowable(t); |
330 |
if (t2 != null) { |
331 |
if (l == null) { |
332 |
l = new ArrayList<ErrorManager.Annotation>(1); |
333 |
} else { |
334 |
l = new ArrayList<ErrorManager.Annotation>(l); |
335 |
} |
336 |
l.add(new Ann(UNKNOWN, null, null, t2, null)); |
337 |
} |
338 |
} |
339 |
if (t instanceof SAXParseException) { |
340 |
// For some reason these fail to come with useful data, like location. |
341 |
SAXParseException spe = (SAXParseException)t; |
342 |
String pubid = spe.getPublicId(); |
343 |
String sysid = spe.getSystemId(); |
344 |
if (pubid != null || sysid != null) { |
345 |
int col = spe.getColumnNumber(); |
346 |
int line = spe.getLineNumber(); |
347 |
String msg; |
348 |
if (col != -1 || line != -1) { |
349 |
msg = NbBundle.getMessage(NbErrorManager.class, "EXC_sax_parse_col_line", new Object[] {String.valueOf(pubid), String.valueOf(sysid), new Integer(col), new Integer(line)}); |
350 |
} else { |
351 |
msg = NbBundle.getMessage(NbErrorManager.class, "EXC_sax_parse", String.valueOf(pubid), String.valueOf(sysid)); |
352 |
} |
125 |
} |
353 |
if (l == null) { |
126 |
if (res instanceof LogRecord[]) { |
354 |
l = new ArrayList<ErrorManager.Annotation>(1); |
127 |
LogRecord[] arr = (LogRecord[])res; |
355 |
} else { |
128 |
l.addAll(Arrays.asList(arr)); |
356 |
l = new ArrayList<ErrorManager.Annotation>(l); |
|
|
357 |
} |
129 |
} |
358 |
l.add(new Ann(UNKNOWN, msg, null, null, null)); |
|
|
359 |
} |
130 |
} |
|
|
131 |
collect = collect.getCause(); |
360 |
} |
132 |
} |
|
|
133 |
|
134 |
if (add != null) { |
135 |
l.add(add); |
136 |
} |
137 |
|
361 |
|
138 |
|
362 |
if (recursively) { |
139 |
if (recursively) { |
363 |
if (l != null) { |
140 |
if (l != null) { |
364 |
ArrayList<Annotation> al = new ArrayList<Annotation>(); |
141 |
ArrayList al = new ArrayList(); |
365 |
for (Iterator<Annotation> i = l.iterator(); i.hasNext(); ) { |
142 |
for (Iterator i = l.iterator(); i.hasNext(); ) { |
366 |
Annotation ano = i.next(); |
143 |
LogRecord ano = (LogRecord)i.next(); |
367 |
Throwable t1 = ano.getStackTrace(); |
144 |
Throwable t1 = ano.getThrown(); |
368 |
if ((t1 != null) && (! alreadyVisited.contains(t1))) { |
145 |
if ((t1 != null) && (! alreadyVisited.contains(t1))) { |
369 |
alreadyVisited.add(t1); |
146 |
alreadyVisited.add(t1); |
370 |
Annotation[] tmpAnnoArray = findAnnotations0(t1, true, alreadyVisited); |
147 |
LogRecord[] tmpAnnoArray = findAnnotations0(t1, null, true, alreadyVisited); |
371 |
if ((tmpAnnoArray != null) && (tmpAnnoArray.length > 0)) { |
148 |
if ((tmpAnnoArray != null) && (tmpAnnoArray.length > 0)) { |
372 |
al.addAll(Arrays.asList(tmpAnnoArray)); |
149 |
al.addAll(Arrays.asList(tmpAnnoArray)); |
373 |
} |
150 |
} |
Lines 376-520
Link Here
|
376 |
l.addAll(al); |
153 |
l.addAll(al); |
377 |
} |
154 |
} |
378 |
} |
155 |
} |
|
|
156 |
|
379 |
Throwable cause = t.getCause(); |
157 |
Throwable cause = t.getCause(); |
380 |
if (cause != null) { |
158 |
if (cause != null) { |
381 |
Annotation[] extras = findAnnotations0(cause, true, alreadyVisited); |
159 |
LogRecord[] extras = findAnnotations0(cause, null, true, alreadyVisited); |
382 |
if (extras != null && extras.length > 0) { |
160 |
if (extras != null && extras.length > 0) { |
383 |
if (l == null) { |
161 |
if (l == null) { |
384 |
l = new ArrayList<Annotation>(); |
162 |
l = new ArrayList<LogRecord>(); |
385 |
} |
163 |
} |
386 |
l.addAll(Arrays.asList(extras)); |
164 |
l.addAll(Arrays.asList(extras)); |
387 |
} |
165 |
} |
388 |
} |
166 |
} |
389 |
|
167 |
|
390 |
Annotation[] arr; |
168 |
LogRecord[] arr; |
391 |
if (l == null) { |
169 |
if (l == null) { |
392 |
arr = null; |
170 |
arr = null; |
393 |
} else { |
171 |
} else { |
394 |
arr = new Annotation[l.size ()]; |
172 |
arr = new LogRecord[l.size()]; |
395 |
l.toArray (arr); |
173 |
l.toArray(arr); |
396 |
} |
174 |
} |
397 |
|
175 |
|
398 |
return arr; |
176 |
return arr; |
399 |
} |
177 |
} |
400 |
|
178 |
|
401 |
public String toString() { |
|
|
402 |
return super.toString() + "<" + logger + ">"; // NOI18N |
403 |
} |
404 |
|
405 |
private static volatile Thread lastThread; |
406 |
private static boolean enterLog() { |
407 |
if (lastThread == Thread.currentThread()) { |
408 |
new Exception("using error manager from inside a logger").printStackTrace(); // NOI18N |
409 |
return true; |
410 |
} |
411 |
lastThread = Thread.currentThread(); |
412 |
return false; |
413 |
} |
414 |
|
415 |
private static void exitLog() { |
416 |
lastThread = null; |
417 |
} |
418 |
|
419 |
/** Implementation of annotation interface. |
420 |
*/ |
421 |
private static final class Ann extends Object |
422 |
implements ErrorManager.Annotation { |
423 |
private int severity; |
424 |
private String message; |
425 |
private String localizedMessage; |
426 |
private Throwable stackTrace; |
427 |
private Date date; |
428 |
|
429 |
/** Constructor. |
430 |
*/ |
431 |
public Ann ( |
432 |
int severity, |
433 |
String message, |
434 |
String localizedMessage, |
435 |
Throwable stackTrace, |
436 |
Date date |
437 |
) { |
438 |
this.severity = severity; |
439 |
this.message = message; |
440 |
this.localizedMessage = localizedMessage; |
441 |
this.stackTrace = stackTrace; |
442 |
this.date = date; |
443 |
} |
444 |
|
445 |
/** Non-localized message. |
446 |
* @return associated message or null |
447 |
*/ |
448 |
public String getMessage() { |
449 |
return message; |
450 |
} |
451 |
/** Localized message. |
452 |
* @return message to be presented to the user or null |
453 |
*/ |
454 |
public String getLocalizedMessage() { |
455 |
return localizedMessage; |
456 |
} |
457 |
/** Stack trace. The stack trace should locate the method |
458 |
* and possition in the method where error occured. |
459 |
* |
460 |
* @return exception representing the location of error or null |
461 |
*/ |
462 |
public Throwable getStackTrace() { |
463 |
return stackTrace; |
464 |
} |
465 |
/** Date when the exception occured. |
466 |
* @return the date or null |
467 |
*/ |
468 |
public java.util.Date getDate() { |
469 |
return date; |
470 |
} |
471 |
/** Severity of the exception. |
472 |
* @return number representing the severity |
473 |
*/ |
474 |
public int getSeverity() { |
475 |
return severity; |
476 |
} |
477 |
|
478 |
public String toString() { |
479 |
return "NbEM.Ann[severity=" + severity + ",message=" + message + ",localizedMessage=" + localizedMessage + ",stackTrace=" + stackTrace + ",date=" + date + "]"; // NOI18N |
480 |
} |
481 |
|
482 |
} // end of Ann |
483 |
|
484 |
/** |
179 |
/** |
485 |
* Another final class that is used to communicate with |
180 |
* Another final class that is used to communicate with |
486 |
* NotifyException and provides enough information to the dialog. |
181 |
* NotifyException and provides enough information to the dialog. |
487 |
*/ |
182 |
*/ |
488 |
final class Exc |
183 |
final class Exc { |
489 |
{ |
|
|
490 |
/** the original throwable */ |
184 |
/** the original throwable */ |
491 |
private Throwable t; |
185 |
private Throwable t; |
492 |
private Date d; |
186 |
private Date d; |
493 |
private Annotation[] arr; |
187 |
private LogRecord[] arr; |
494 |
private Annotation[] arrAll; // all - recursively |
188 |
private LogRecord[] arrAll; // all - recursively |
495 |
private int severity; |
189 |
private Level severity; |
496 |
|
190 |
|
497 |
/** @param severity if -1 then we will compute the |
191 |
/** @param severity if -1 then we will compute the |
498 |
* severity from annotations |
192 |
* severity from annotations |
499 |
*/ |
193 |
*/ |
500 |
Exc (Throwable t, int severity, Annotation[] arr, Annotation[] arrAll) { |
194 |
Exc(Throwable t, Level severity, LogRecord[] arr, LogRecord[] arrAll) { |
501 |
this.t = t; |
195 |
this.t = t; |
502 |
this.severity = severity; |
196 |
this.severity = severity; |
503 |
this.arr = arr == null ? new Annotation[0] : arr; |
197 |
this.arr = arr == null ? new LogRecord[0] : arr; |
504 |
this.arrAll = arrAll == null ? new Annotation[0] : arrAll; |
198 |
this.arrAll = arrAll == null ? new LogRecord[0] : arrAll; |
505 |
} |
199 |
} |
506 |
|
200 |
|
507 |
/** @return message */ |
201 |
/** @return message */ |
508 |
String getMessage () { |
202 |
String getMessage() { |
509 |
String m = t.getMessage(); |
203 |
String m = t.getMessage(); |
510 |
if (m != null) { |
204 |
if (m != null) { |
511 |
return m; |
205 |
return m; |
512 |
} |
206 |
} |
513 |
return (String)find (1); |
207 |
return (String)find(1); |
514 |
} |
208 |
} |
515 |
|
209 |
|
516 |
/** @return localized message */ |
210 |
/** @return localized message */ |
517 |
String getLocalizedMessage () { |
211 |
String getLocalizedMessage() { |
518 |
String m = t.getLocalizedMessage(); |
212 |
String m = t.getLocalizedMessage(); |
519 |
if (m != null && !m.equals(t.getMessage())) { |
213 |
if (m != null && !m.equals(t.getMessage())) { |
520 |
return m; |
214 |
return m; |
Lines 524-537
Link Here
|
524 |
return (String)find(2); |
218 |
return (String)find(2); |
525 |
} |
219 |
} |
526 |
for (int i = 0; i < arrAll.length; i++) { |
220 |
for (int i = 0; i < arrAll.length; i++) { |
527 |
String s = arrAll[i].getLocalizedMessage (); |
221 |
String s = NbErrorManager.getLocalizedMessage(arrAll[i]); |
528 |
if (s != null) { |
222 |
if (s != null) { |
529 |
return s; |
223 |
return s; |
530 |
} |
224 |
} |
531 |
} |
225 |
} |
532 |
return m; |
226 |
return m; |
533 |
} |
227 |
} |
534 |
|
228 |
|
535 |
boolean isLocalized() { |
229 |
boolean isLocalized() { |
536 |
String m = t.getLocalizedMessage(); |
230 |
String m = t.getLocalizedMessage(); |
537 |
if (m != null && !m.equals(t.getMessage())) { |
231 |
if (m != null && !m.equals(t.getMessage())) { |
Lines 542-597
Link Here
|
542 |
return (String)find(2) != null; |
236 |
return (String)find(2) != null; |
543 |
} |
237 |
} |
544 |
for (int i = 0; i < arrAll.length; i++) { |
238 |
for (int i = 0; i < arrAll.length; i++) { |
545 |
String s = arrAll[i].getLocalizedMessage (); |
239 |
String s = NbErrorManager.getLocalizedMessage(arrAll[i]); |
546 |
if (s != null) { |
240 |
if (s != null) { |
547 |
return true; |
241 |
return true; |
548 |
} |
242 |
} |
549 |
} |
243 |
} |
550 |
return false; |
244 |
return false; |
551 |
} |
245 |
} |
552 |
|
246 |
|
553 |
/** @return class name of the exception */ |
247 |
/** @return class name of the exception */ |
554 |
String getClassName () { |
248 |
String getClassName() { |
555 |
return (String)find (3); |
249 |
return (String)find(3); |
556 |
} |
250 |
} |
557 |
|
251 |
|
558 |
/** @return the severity of the exception */ |
252 |
/** @return the severity of the exception */ |
559 |
int getSeverity () { |
253 |
Level getSeverity() { |
560 |
if (severity != UNKNOWN) { |
254 |
if (severity != null) { |
561 |
return severity; |
255 |
return severity; |
562 |
} |
256 |
} |
563 |
|
257 |
|
564 |
Annotation[] anns = (arrAll != null) ? arrAll : arr; |
258 |
LogRecord[] anns = (arrAll != null) ? arrAll : arr; |
565 |
for (int i = 0; i < anns.length; i++) { |
259 |
for (int i = 0; i < anns.length; i++) { |
566 |
int s = anns[i].getSeverity (); |
260 |
Level s = anns[i].getLevel(); |
567 |
if (s > severity) { |
261 |
if (severity == null || s.intValue() > severity.intValue()) { |
568 |
severity = s; |
262 |
severity = s; |
569 |
} |
263 |
} |
570 |
} |
264 |
} |
571 |
|
265 |
|
572 |
if (severity == UNKNOWN) { |
266 |
if (severity == null || severity == Level.ALL) { |
573 |
// no severity specified, assume this is an error |
267 |
// no severity specified, assume this is an error |
574 |
severity = t instanceof Error ? ERROR : EXCEPTION; |
268 |
severity = t instanceof Error ? Level.SEVERE : Level.WARNING; |
575 |
} |
269 |
} |
576 |
|
270 |
|
577 |
return severity; |
271 |
return severity; |
578 |
} |
272 |
} |
579 |
|
273 |
|
580 |
/** @return date assigned to the exception */ |
274 |
/** @return date assigned to the exception */ |
581 |
Date getDate () { |
275 |
Date getDate() { |
582 |
if (d == null) { |
276 |
if (d == null) { |
583 |
d = (Date)find (4); |
277 |
d = (Date)find(4); |
584 |
} |
278 |
} |
585 |
return d; |
279 |
return d; |
586 |
} |
280 |
} |
587 |
|
281 |
|
588 |
void printStackTrace (PrintStream ps) { |
282 |
void printStackTrace(PrintStream ps) { |
589 |
printStackTrace(new PrintWriter(new OutputStreamWriter(ps))); |
283 |
printStackTrace(new PrintWriter(new OutputStreamWriter(ps))); |
590 |
} |
284 |
} |
591 |
/** Prints stack trace of all annotations and if |
285 |
/** Prints stack trace of all annotations and if |
592 |
* there is no annotation trace then of the exception |
286 |
* there is no annotation trace then of the exception |
593 |
*/ |
287 |
*/ |
594 |
void printStackTrace (PrintWriter pw) { |
288 |
void printStackTrace(PrintWriter pw) { |
595 |
// #19487: don't go into an endless loop here |
289 |
// #19487: don't go into an endless loop here |
596 |
printStackTrace(pw, new HashSet<Throwable>(10)); |
290 |
printStackTrace(pw, new HashSet<Throwable>(10)); |
597 |
} |
291 |
} |
Lines 599-620
Link Here
|
599 |
private void printStackTrace(PrintWriter pw, Set<Throwable> nestingCheck) { |
293 |
private void printStackTrace(PrintWriter pw, Set<Throwable> nestingCheck) { |
600 |
if (t != null && !nestingCheck.add(t)) { |
294 |
if (t != null && !nestingCheck.add(t)) { |
601 |
// Unlocalized log message - this is for developers of NB, not users |
295 |
// Unlocalized log message - this is for developers of NB, not users |
602 |
log(ErrorManager.WARNING, "WARNING - ErrorManager detected cyclic exception nesting:"); // NOI18N |
296 |
Logger l = Logger.getAnonymousLogger(); |
|
|
297 |
l.warning("WARNING - ErrorManager detected cyclic exception nesting:"); // NOI18N |
603 |
Iterator it = nestingCheck.iterator(); |
298 |
Iterator it = nestingCheck.iterator(); |
604 |
while (it.hasNext()) { |
299 |
while (it.hasNext()) { |
605 |
Throwable t = (Throwable)it.next(); |
300 |
Throwable t = (Throwable)it.next(); |
606 |
log(ErrorManager.WARNING, "\t" + t); // NOI18N |
301 |
l.warning("\t" + t); // NOI18N |
607 |
Annotation[] anns = findAnnotations(t); |
302 |
LogRecord[] anns = findAnnotations(t, null); |
608 |
if (anns != null) { |
303 |
if (anns != null) { |
609 |
for (int i = 0; i < anns.length; i++) { |
304 |
for (int i = 0; i < anns.length; i++) { |
610 |
Throwable t2 = anns[i].getStackTrace(); |
305 |
Throwable t2 = anns[i].getThrown(); |
611 |
if (t2 != null) { |
306 |
if (t2 != null) { |
612 |
log(ErrorManager.WARNING, "\t=> " + t2); // NOI18N |
307 |
l.warning("\t=> " + t2); // NOI18N |
613 |
} |
308 |
} |
614 |
} |
309 |
} |
615 |
} |
310 |
} |
616 |
} |
311 |
} |
617 |
log(ErrorManager.WARNING, "Be sure not to annotate an exception with itself, directly or indirectly."); // NOI18N |
312 |
l.warning("Be sure not to annotate an exception with itself, directly or indirectly."); // NOI18N |
618 |
return; |
313 |
return; |
619 |
} |
314 |
} |
620 |
/*Heaeder |
315 |
/*Heaeder |
Lines 629-641
Link Here
|
629 |
pw.print("<no message>"); // NOI18N |
324 |
pw.print("<no message>"); // NOI18N |
630 |
} |
325 |
} |
631 |
pw.println (); |
326 |
pw.println (); |
632 |
*/ |
327 |
*/ |
633 |
/*Annotations */ |
328 |
/*Annotations */ |
634 |
for (int i = 0; i < arr.length; i++) { |
329 |
for (int i = 0; i < arr.length; i++) { |
635 |
if (arr[i] == null) continue; |
330 |
if (arr[i] == null) continue; |
636 |
|
331 |
|
637 |
Throwable thr = arr[i].getStackTrace(); |
332 |
Throwable thr = arr[i].getThrown(); |
638 |
String annotation = arr[i].getLocalizedMessage(); |
333 |
String annotation = NbErrorManager.getLocalizedMessage(arr[i]); |
639 |
|
334 |
|
640 |
if (annotation == null) annotation = arr[i].getMessage(); |
335 |
if (annotation == null) annotation = arr[i].getMessage(); |
641 |
/* |
336 |
/* |
Lines 645-655
Link Here
|
645 |
|
340 |
|
646 |
if (annotation != null) { |
341 |
if (annotation != null) { |
647 |
if (thr == null) { |
342 |
if (thr == null) { |
648 |
pw.println ("Annotation: "+annotation);// NOI18N |
343 |
pw.println("Annotation: "+annotation);// NOI18N |
649 |
} |
344 |
} |
650 |
//else pw.println ("Nested annotation: "+annotation);// NOI18N |
345 |
//else pw.println ("Nested annotation: "+annotation);// NOI18N |
651 |
} |
346 |
} |
652 |
} |
347 |
} |
653 |
|
348 |
|
654 |
// ok, print trace of the original exception too |
349 |
// ok, print trace of the original exception too |
655 |
// Attempt to show an annotation indicating where the exception |
350 |
// Attempt to show an annotation indicating where the exception |
Lines 670-715
Link Here
|
670 |
break; |
365 |
break; |
671 |
} |
366 |
} |
672 |
} |
367 |
} |
673 |
String[] tLines = decompose (t); |
368 |
String[] tLines = decompose(t); |
674 |
for (int i = 0; i < tLines.length; i++) { |
369 |
for (int i = 0; i < tLines.length; i++) { |
675 |
if (i == idx) { |
370 |
if (i == idx) { |
676 |
pw.print ("[catch]"); // NOI18N |
371 |
pw.print("[catch]"); // NOI18N |
677 |
// Also translate following tab -> space since formatting is bad in |
372 |
// Also translate following tab -> space since formatting is bad in |
678 |
// Output Window (#8104) and some mail agents screw it up etc. |
373 |
// Output Window (#8104) and some mail agents screw it up etc. |
679 |
if (tLines[i].charAt (0) == '\t') { |
374 |
if (tLines[i].charAt(0) == '\t') { |
680 |
pw.print (' '); |
375 |
pw.print(' '); |
681 |
tLines[i] = tLines[i].substring (1); |
376 |
tLines[i] = tLines[i].substring(1); |
|
|
377 |
} |
682 |
} |
378 |
} |
|
|
379 |
pw.println(tLines[i]); |
683 |
} |
380 |
} |
684 |
pw.println (tLines[i]); |
|
|
685 |
} |
381 |
} |
686 |
} |
382 |
/*Nested annotations */ |
687 |
/*Nested annotations */ |
|
|
688 |
for (int i = 0; i < arr.length; i++) { |
383 |
for (int i = 0; i < arr.length; i++) { |
689 |
if (arr[i] == null) continue; |
384 |
if (arr[i] == null) continue; |
690 |
|
385 |
|
691 |
Throwable thr = arr[i].getStackTrace(); |
386 |
Throwable thr = arr[i].getThrown(); |
692 |
if (thr != null) { |
387 |
if (thr != null) { |
693 |
Annotation[] ans = findAnnotations (thr); |
388 |
LogRecord[] ans = findAnnotations(thr, null); |
694 |
Exc ex = new Exc (thr, 0, ans, null); |
389 |
Exc ex = new Exc(thr, null, ans, null); |
695 |
pw.println("==>"); // NOI18N |
390 |
pw.println("==>"); // NOI18N |
696 |
ex.printStackTrace(pw, nestingCheck); |
391 |
ex.printStackTrace(pw, nestingCheck); |
697 |
} |
392 |
} |
698 |
} |
393 |
} |
699 |
} |
394 |
} |
700 |
|
395 |
|
701 |
/** Get a throwable's stack trace, decomposed into individual lines. */ |
396 |
/** Get a throwable's stack trace, decomposed into individual lines. */ |
702 |
private String[] decompose (Throwable t) { |
397 |
private String[] decompose(Throwable t) { |
703 |
StringWriter sw = new StringWriter (); |
398 |
StringWriter sw = new StringWriter(); |
704 |
t.printStackTrace (new PrintWriter (sw)); |
399 |
t.printStackTrace(new PrintWriter(sw)); |
705 |
StringTokenizer tok = new StringTokenizer (sw.toString (), "\n\r"); // NOI18N |
400 |
StringTokenizer tok = new StringTokenizer(sw.toString(), "\n\r"); // NOI18N |
706 |
int c = tok.countTokens (); |
401 |
int c = tok.countTokens(); |
707 |
String[] lines = new String[c]; |
402 |
String[] lines = new String[c]; |
708 |
for (int i = 0; i < c; i++) |
403 |
for (int i = 0; i < c; i++) |
709 |
lines[i] = tok.nextToken (); |
404 |
lines[i] = tok.nextToken(); |
710 |
return lines; |
405 |
return lines; |
711 |
} |
406 |
} |
712 |
|
407 |
|
713 |
/** |
408 |
/** |
714 |
* Method that iterates over annotations to find out |
409 |
* Method that iterates over annotations to find out |
715 |
* the first annotation that brings the requested value. |
410 |
* the first annotation that brings the requested value. |
Lines 717-726
Link Here
|
717 |
* @param kind what to look for (1, 2, 3, 4, ...); |
412 |
* @param kind what to look for (1, 2, 3, 4, ...); |
718 |
* @return the found object |
413 |
* @return the found object |
719 |
*/ |
414 |
*/ |
720 |
private Object find (int kind) { |
415 |
private Object find(int kind) { |
721 |
return find(kind, true); |
416 |
return find(kind, true); |
722 |
} |
417 |
} |
723 |
|
418 |
|
724 |
/** |
419 |
/** |
725 |
* Method that iterates over annotations to find out |
420 |
* Method that iterates over annotations to find out |
726 |
* the first annotation that brings the requested value. |
421 |
* the first annotation that brings the requested value. |
Lines 728-787
Link Here
|
728 |
* @param kind what to look for (1, 2, 3, 4, ...); |
423 |
* @param kind what to look for (1, 2, 3, 4, ...); |
729 |
* @return the found object |
424 |
* @return the found object |
730 |
*/ |
425 |
*/ |
731 |
private Object find (int kind, boolean def) { |
426 |
private Object find(int kind, boolean def) { |
732 |
for (int i = 0; i < arr.length; i++) { |
427 |
for (int i = 0; i < arr.length; i++) { |
733 |
Annotation a = arr[i]; |
428 |
LogRecord a = arr[i]; |
734 |
|
429 |
|
735 |
Object o = null; |
430 |
Object o = null; |
736 |
switch (kind) { |
431 |
switch (kind) { |
737 |
case 1: // message |
432 |
case 1: // message |
738 |
o = a.getMessage (); break; |
433 |
o = a.getMessage(); break; |
739 |
case 2: // localized |
434 |
case 2: // localized |
740 |
o = a.getLocalizedMessage (); break; |
435 |
o = NbErrorManager.getLocalizedMessage(a); break; |
741 |
case 3: // class name |
436 |
case 3: // class name |
742 |
{ |
437 |
{ |
743 |
Throwable t = a.getStackTrace (); |
438 |
Throwable t = a.getThrown(); |
744 |
o = t == null ? null : t.getClass().getName(); |
439 |
o = t == null ? null : t.getClass().getName(); |
745 |
break; |
440 |
break; |
746 |
} |
441 |
} |
747 |
case 4: // date |
442 |
case 4: // date |
748 |
o = a.getDate (); break; |
443 |
o = new Date(a.getMillis()); break; |
749 |
} |
444 |
} |
750 |
|
445 |
|
751 |
if (o != null) { |
446 |
if (o != null) { |
752 |
return o; |
447 |
return o; |
753 |
} |
448 |
} |
754 |
} |
449 |
} |
755 |
|
450 |
|
756 |
if (!def) |
451 |
if (!def) |
757 |
return null; |
452 |
return null; |
758 |
switch (kind) { |
453 |
switch (kind) { |
759 |
case 1: // message |
454 |
case 1: // message |
760 |
return t.getMessage (); |
455 |
return t.getMessage(); |
761 |
case 2: // loc.msg. |
456 |
case 2: // loc.msg. |
762 |
return t.getLocalizedMessage(); |
457 |
return t.getLocalizedMessage(); |
763 |
case 3: // class name |
458 |
case 3: // class name |
764 |
return t.getClass ().getName (); |
459 |
return t.getClass().getName(); |
765 |
case 4: // date |
460 |
case 4: // date |
766 |
return new Date (); |
461 |
return new Date(); |
767 |
default: |
462 |
default: |
768 |
throw new IllegalArgumentException ( |
463 |
throw new IllegalArgumentException( |
769 |
"Unknown " + new Integer (kind) // NOI18N |
464 |
"Unknown " + new Integer(kind) // NOI18N |
770 |
); |
465 |
); |
771 |
} |
|
|
772 |
} |
773 |
} |
774 |
|
775 |
/** Instances are created in awt.EventDispatchThread */ |
776 |
public static final class AWTHandler |
777 |
{ |
778 |
/** The name MUST be handle and MUST be public */ |
779 |
public static void handle(Throwable t) { |
780 |
// Either org.netbeans or org.netbeans.core.execution pkgs: |
781 |
if (t.getClass().getName().endsWith(".ExitSecurityException")) { // NOI18N |
782 |
return; |
783 |
} |
466 |
} |
784 |
ErrorManager.getDefault().notify((ERROR << 1), t); |
|
|
785 |
} |
467 |
} |
786 |
} |
468 |
} |
|
|
469 |
|
787 |
} |
470 |
} |