View Javadoc
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 == null) for 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 }