1 /**
2  * Logback: the reliable, generic, fast and flexible logging framework.
3  * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4  *
5  * This program and the accompanying materials are dual-licensed under
6  * either the terms of the Eclipse Public License v1.0 as published by
7  * the Eclipse Foundation
8  *
9  *   or (per the licensee's choosing)
10  *
11  * under the terms of the GNU Lesser General Public License version 2.1
12  * as published by the Free Software Foundation.
13  */

14 package ch.qos.logback.classic.spi;
15
16 import ch.qos.logback.core.CoreConstants;
17
18 import java.lang.reflect.InvocationTargetException;
19 import java.lang.reflect.Method;
20
21 public class ThrowableProxy implements IThrowableProxy {
22
23     private Throwable throwable;
24     private String className;
25     private String message;
26     // package-private because of ThrowableProxyUtil
27     StackTraceElementProxy[] stackTraceElementProxyArray;
28     // package-private because of ThrowableProxyUtil
29     int commonFrames;
30     private ThrowableProxy cause;
31     private ThrowableProxy[] suppressed = NO_SUPPRESSED;
32
33     private transient PackagingDataCalculator packagingDataCalculator;
34     private boolean calculatedPackageData = false;
35
36     private static final Method GET_SUPPRESSED_METHOD;
37
38     static {
39         Method method = null;
40         try {
41             method = Throwable.class.getMethod("getSuppressed");
42         } catch (NoSuchMethodException e) {
43             // ignore, will get thrown in Java < 7
44         }
45         GET_SUPPRESSED_METHOD = method;
46     }
47
48     private static final ThrowableProxy[] NO_SUPPRESSED = new ThrowableProxy[0];
49
50     public ThrowableProxy(Throwable throwable) {
51
52         this.throwable = throwable;
53         this.className = throwable.getClass().getName();
54         this.message = throwable.getMessage();
55         this.stackTraceElementProxyArray = ThrowableProxyUtil.steArrayToStepArray(throwable.getStackTrace());
56
57         Throwable nested = throwable.getCause();
58
59         if (nested != null) {
60             this.cause = new ThrowableProxy(nested);
61             this.cause.commonFrames = ThrowableProxyUtil.findNumberOfCommonFrames(nested.getStackTrace(), stackTraceElementProxyArray);
62         }
63         if (GET_SUPPRESSED_METHOD != null) {
64             // this will only execute on Java 7
65             try {
66                 Object obj = GET_SUPPRESSED_METHOD.invoke(throwable);
67                 if (obj instanceof Throwable[]) {
68                     Throwable[] throwableSuppressed = (Throwable[]) obj;
69                     if (throwableSuppressed.length > 0) {
70                         suppressed = new ThrowableProxy[throwableSuppressed.length];
71                         for (int i = 0; i < throwableSuppressed.length; i++) {
72                             this.suppressed[i] = new ThrowableProxy(throwableSuppressed[i]);
73                             this.suppressed[i].commonFrames = ThrowableProxyUtil.findNumberOfCommonFrames(throwableSuppressed[i].getStackTrace(),
74                                             stackTraceElementProxyArray);
75                         }
76                     }
77                 }
78             } catch (IllegalAccessException e) {
79                 // ignore
80             } catch (InvocationTargetException e) {
81                 // ignore
82             }
83         }
84
85     }
86
87     public Throwable getThrowable() {
88         return throwable;
89     }
90
91     public String getMessage() {
92         return message;
93     }
94
95     /*
96      * (non-Javadoc)
97      * 
98      * @see ch.qos.logback.classic.spi.IThrowableProxy#getClassName()
99      */

100     public String getClassName() {
101         return className;
102     }
103
104     public StackTraceElementProxy[] getStackTraceElementProxyArray() {
105         return stackTraceElementProxyArray;
106     }
107
108     public int getCommonFrames() {
109         return commonFrames;
110     }
111
112     /*
113      * (non-Javadoc)
114      * 
115      * @see ch.qos.logback.classic.spi.IThrowableProxy#getCause()
116      */

117     public IThrowableProxy getCause() {
118         return cause;
119     }
120
121     public IThrowableProxy[] getSuppressed() {
122         return suppressed;
123     }
124
125     public PackagingDataCalculator getPackagingDataCalculator() {
126         // if original instance (non-deserialized), and packagingDataCalculator
127         // is not already initialized, then create an instance.
128         // here we assume that (throwable == nullfor deserialized instances
129         if (throwable != null && packagingDataCalculator == null) {
130             packagingDataCalculator = new PackagingDataCalculator();
131         }
132         return packagingDataCalculator;
133     }
134
135     public void calculatePackagingData() {
136         if (calculatedPackageData) {
137             return;
138         }
139         PackagingDataCalculator pdc = this.getPackagingDataCalculator();
140         if (pdc != null) {
141             calculatedPackageData = true;
142             pdc.calculate(this);
143         }
144     }
145
146     public void fullDump() {
147         StringBuilder builder = new StringBuilder();
148         for (StackTraceElementProxy step : stackTraceElementProxyArray) {
149             String string = step.toString();
150             builder.append(CoreConstants.TAB).append(string);
151             ThrowableProxyUtil.subjoinPackagingData(builder, step);
152             builder.append(CoreConstants.LINE_SEPARATOR);
153         }
154         System.out.println(builder.toString());
155     }
156
157 }
158