001 /**
002 * <copyright>
003 *
004 * Copyright (c) 2004-2007 IBM Corporation and others.
005 * All rights reserved. This program and the accompanying materials
006 * are made available under the terms of the Eclipse Public License v1.0
007 * which accompanies this distribution, and is available at
008 * http://www.eclipse.org/legal/epl-v10.html
009 *
010 * Contributors:
011 * IBM - Initial API and implementation
012 *
013 * </copyright>
014 *
015 * $Id: BasicDiagnostic.java,v 1.15 2009/04/18 11:45:26 emerks Exp $
016 */
017 package org.eclipse.emf.common.util;
018
019 import java.util.ArrayList;
020 import java.util.Collections;
021 import java.util.List;
022
023 import org.eclipse.core.runtime.IStatus;
024
025 import org.eclipse.emf.common.EMFPlugin;
026
027
028 /**
029 * A basic implementation of a diagnostic that that also acts as a chain.
030 */
031 public class BasicDiagnostic implements Diagnostic, DiagnosticChain
032 {
033 /**
034 * The severity.
035 * @see #getSeverity
036 */
037 protected int severity;
038
039 /**
040 * The message.
041 * @see #getMessage
042 */
043 protected String message;
044
045 /**
046 * The message.
047 * @see #getMessage
048 */
049 protected List<Diagnostic> children;
050
051 /**
052 * The data.
053 * @see #getData
054 */
055 protected List<?> data;
056
057 /**
058 * The source.
059 * @see #getSource
060 */
061 protected String source;
062
063 /**
064 * The code.
065 * @see #getCode
066 */
067 protected int code;
068
069 /**
070 * Default Constructor (no initialization for local parameters)
071 */
072 public BasicDiagnostic()
073 {
074 super();
075 }
076
077 public BasicDiagnostic(String source, int code, String message, Object[] data)
078 {
079 this.source = source;
080 this.code = code;
081 this.message = message;
082 this.data = dataAsList(data);
083 }
084
085 public BasicDiagnostic(int severity, String source, int code, String message, Object[] data)
086 {
087 this(source, code, message, data);
088 this.severity = severity;
089 }
090
091 public BasicDiagnostic(String source, int code, List<? extends Diagnostic> children, String message, Object[] data)
092 {
093 this(source, code, message, data);
094 if (children != null)
095 {
096 for (Diagnostic diagnostic : children)
097 {
098 add(diagnostic);
099 }
100 }
101 }
102
103 protected List<?> dataAsList(Object [] data)
104 {
105 if (data == null)
106 {
107 return Collections.EMPTY_LIST;
108 }
109 else
110 {
111 Object [] copy = new Object [data.length];
112 System.arraycopy(data, 0, copy, 0, data.length);
113 return new BasicEList.UnmodifiableEList<Object>(copy.length, copy);
114 }
115 }
116
117 protected void setSeverity(int severity)
118 {
119 this.severity = severity;
120 }
121
122 public int getSeverity()
123 {
124 return severity;
125 }
126
127 public String getMessage()
128 {
129 return message;
130 }
131
132 public List<?> getData()
133 {
134 return data;
135 }
136
137 public List<Diagnostic> getChildren()
138 {
139 if (children == null)
140 {
141 return Collections.emptyList();
142 }
143 else
144 {
145 return Collections.unmodifiableList(children);
146 }
147 }
148
149 protected void setSource(String source)
150 {
151 this.source = source;
152 }
153
154 public String getSource()
155 {
156 return source;
157 }
158
159 protected void setCode(int code)
160 {
161 this.code = code;
162 }
163
164 public int getCode()
165 {
166 return code;
167 }
168
169 public void add(Diagnostic diagnostic)
170 {
171 if (children == null)
172 {
173 children = new BasicEList<Diagnostic>();
174 }
175
176 children.add(diagnostic);
177 int childSeverity = diagnostic.getSeverity();
178 if (childSeverity > getSeverity())
179 {
180 severity = childSeverity;
181 }
182 }
183
184 public void addAll(Diagnostic diagnostic)
185 {
186 for (Diagnostic child : diagnostic.getChildren())
187 {
188 add(child);
189 }
190 }
191
192 public void merge(Diagnostic diagnostic)
193 {
194 if (diagnostic.getChildren().isEmpty())
195 {
196 add(diagnostic);
197 }
198 else
199 {
200 addAll(diagnostic);
201 }
202 }
203
204 public int recomputeSeverity()
205 {
206 if (children != null)
207 {
208 severity = OK;
209 for (Diagnostic child : children)
210 {
211 int childSeverity = child instanceof BasicDiagnostic ? ((BasicDiagnostic)child).recomputeSeverity() : child.getSeverity();
212 if (childSeverity > severity)
213 {
214 severity = childSeverity;
215 }
216 }
217 }
218
219 return severity;
220 }
221
222 /**
223 * Returns the first throwable object available in the {@link #data} list,
224 * which is set when this diagnostic is instantiated.
225 */
226 public Throwable getException()
227 {
228 List<?> data = getData();
229 if (data != null)
230 {
231 for (Object datum : data)
232 {
233 if (datum instanceof Throwable)
234 {
235 return (Throwable)datum;
236 }
237 }
238 }
239 return null;
240 }
241
242 @Override
243 public String toString()
244 {
245 StringBuilder result = new StringBuilder();
246 result.append("Diagnostic ");
247 switch (severity)
248 {
249 case OK:
250 {
251 result.append("OK");
252 break;
253 }
254 case INFO:
255 {
256 result.append("INFO");
257 break;
258 }
259 case WARNING:
260 {
261 result.append("WARNING");
262 break;
263 }
264 case ERROR:
265 {
266 result.append("ERROR");
267 break;
268 }
269 case CANCEL:
270 {
271 result.append("CANCEL");
272 break;
273 }
274 default:
275 {
276 result.append(Integer.toHexString(severity));
277 break;
278 }
279 }
280
281 result.append(" source=");
282 result.append(source);
283
284 result.append(" code=");
285 result.append(code);
286
287 result.append(' ');
288 result.append(message);
289
290 if (data != null)
291 {
292 result.append(" data=");
293 result.append(data);
294 }
295 if (children != null)
296 {
297 result.append(' ');
298 result.append(children);
299 }
300
301 return result.toString();
302 }
303
304 private static class StatusWrapper implements IStatus
305 {
306 protected static final IStatus [] EMPTY_CHILDREN = new IStatus [0];
307
308 protected Throwable throwable;
309 protected Diagnostic diagnostic;
310 protected IStatus [] wrappedChildren;
311
312 public StatusWrapper(Diagnostic diagnostic)
313 {
314 this.diagnostic = diagnostic;
315 }
316
317 public StatusWrapper(DiagnosticException diagnosticException)
318 {
319 throwable = diagnosticException;
320 diagnostic = diagnosticException.getDiagnostic();
321 }
322
323 public IStatus[] getChildren()
324 {
325 if (wrappedChildren == null)
326 {
327 List<Diagnostic> children = diagnostic.getChildren();
328 if (children.isEmpty())
329 {
330 wrappedChildren = EMPTY_CHILDREN;
331 }
332 else
333 {
334 wrappedChildren = new IStatus [children.size()];
335 for (int i = 0; i < wrappedChildren.length; ++i)
336 {
337 wrappedChildren[i] = toIStatus(children.get(i));
338 }
339 }
340 }
341 return wrappedChildren;
342 }
343
344 public int getCode()
345 {
346 return diagnostic.getCode();
347 }
348
349 public Throwable getException()
350 {
351 return throwable != null ? throwable : diagnostic.getException();
352 }
353
354 public String getMessage()
355 {
356 return diagnostic.getMessage();
357 }
358
359 public String getPlugin()
360 {
361 return diagnostic.getSource();
362 }
363
364 public int getSeverity()
365 {
366 return diagnostic.getSeverity();
367 }
368
369 public boolean isMultiStatus()
370 {
371 return !diagnostic.getChildren().isEmpty();
372 }
373
374 public boolean isOK()
375 {
376 return diagnostic.getSeverity() == OK;
377 }
378
379 public boolean matches(int severityMask)
380 {
381 return (diagnostic.getSeverity() & severityMask ) != 0;
382 }
383
384 @Override
385 public String toString()
386 {
387 return diagnostic.toString();
388 }
389
390 public static IStatus convert(Diagnostic diagnostic)
391 {
392 return
393 diagnostic instanceof DiagnosticWrapper ?
394 ((DiagnosticWrapper)diagnostic).status :
395 new StatusWrapper(diagnostic);
396 }
397
398 public static IStatus create(DiagnosticException diagnosticException)
399 {
400 return new StatusWrapper(diagnosticException);
401 }
402 }
403
404 /**
405 * Returns the diagnostic viewed as an {@link IStatus}.
406 */
407 public static IStatus toIStatus(Diagnostic diagnostic)
408 {
409 return StatusWrapper.convert(diagnostic);
410 }
411
412 /**
413 * Returns the diagnostic exception viewed as an {@link IStatus}.
414 */
415 public static IStatus toIStatus(DiagnosticException diagnosticException)
416 {
417 return StatusWrapper.create(diagnosticException);
418 }
419
420 private static class DiagnosticWrapper implements Diagnostic
421 {
422 protected IStatus status;
423 protected List<Diagnostic> wrappedChildren;
424 protected List<Diagnostic> unmodifiableWrappedChildren;
425 protected List<Object> data;
426
427 public DiagnosticWrapper(IStatus status)
428 {
429 this.status = status;
430 }
431
432 public int getCode()
433 {
434 return status.getCode();
435 }
436
437 public String getMessage()
438 {
439 return status.getMessage();
440 }
441
442 public int getSeverity()
443 {
444 return status.getSeverity();
445 }
446
447 public String getSource()
448 {
449 return status.getPlugin();
450 }
451
452 public Throwable getException()
453 {
454 return status.getException();
455 }
456
457 public List<Diagnostic> basicGetChildren()
458 {
459 if (wrappedChildren == null)
460 {
461 IStatus[] children = status.getChildren();
462 if (children.length == 0)
463 {
464 wrappedChildren = new ArrayList<Diagnostic>();
465 }
466 else
467 {
468 wrappedChildren = new ArrayList<Diagnostic>(children.length);
469 for (IStatus child : children)
470 {
471 wrappedChildren.add(toDiagnostic(child));
472 }
473 }
474 }
475 return wrappedChildren;
476 }
477
478 public List<Diagnostic> getChildren()
479 {
480 if (unmodifiableWrappedChildren == null)
481 {
482 unmodifiableWrappedChildren = Collections.unmodifiableList(basicGetChildren());
483 }
484 return unmodifiableWrappedChildren;
485 }
486
487 public List<?> getData()
488 {
489 if (data == null)
490 {
491 List<Object> list = new ArrayList<Object>(2);
492 Throwable exception = getException();
493 if (exception != null)
494 {
495 list.add(exception);
496 }
497 list.add(status);
498 data = Collections.unmodifiableList(list);
499 }
500 return data;
501 }
502
503 public static Diagnostic convert(IStatus status)
504 {
505 return
506 status instanceof StatusWrapper ?
507 ((StatusWrapper)status).diagnostic :
508 new DiagnosticWrapper(status);
509 }
510 }
511
512 public static Diagnostic toDiagnostic(IStatus status)
513 {
514 return DiagnosticWrapper.convert(status);
515 }
516
517 /**
518 * Returns the throwable viewed as a {@link Diagnostic}.
519 *
520 * @param throwable
521 * @return {@link Diagnostic}
522 */
523 public static Diagnostic toDiagnostic(Throwable throwable)
524 {
525 if (throwable instanceof DiagnosticException)
526 {
527 return ((DiagnosticException)throwable).getDiagnostic();
528 }
529 else if (throwable instanceof WrappedException)
530 {
531 return toDiagnostic(throwable.getCause());
532 }
533
534 if (EMFPlugin.IS_ECLIPSE_RUNNING)
535 {
536 Diagnostic diagnostic = EclipseHelper.toDiagnostic(throwable);
537 if (diagnostic != null)
538 {
539 return diagnostic;
540 }
541 }
542
543 String message = throwable.getClass().getName();
544 int index = message.lastIndexOf('.');
545 if (index >= 0)
546 {
547 message = message.substring(index + 1);
548 }
549 if (throwable.getLocalizedMessage() != null)
550 {
551 message = message + ": " + throwable.getLocalizedMessage();
552 }
553
554 BasicDiagnostic basicDiagnostic =
555 new BasicDiagnostic
556 (Diagnostic.ERROR,
557 "org.eclipse.emf.common",
558 0,
559 message,
560 new Object[] { throwable });
561
562 if (throwable.getCause() != null && throwable.getCause() != throwable)
563 {
564 throwable = throwable.getCause();
565 basicDiagnostic.add(toDiagnostic(throwable));
566 }
567
568 return basicDiagnostic;
569 }
570
571 private static class EclipseHelper
572 {
573 public static Diagnostic toDiagnostic(Throwable throwable)
574 {
575 if (throwable instanceof org.eclipse.core.runtime.CoreException)
576 {
577 IStatus status = ((org.eclipse.core.runtime.CoreException)throwable).getStatus();
578 DiagnosticWrapper wrapperDiagnostic = new DiagnosticWrapper(status);
579 Throwable cause = throwable.getCause();
580 if (cause != null && cause != throwable)
581 {
582 wrapperDiagnostic.basicGetChildren().add(BasicDiagnostic.toDiagnostic(cause));
583 }
584 return wrapperDiagnostic;
585 }
586 return null;
587 }
588 }
589 }