View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, 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  /**
19   * Convert a throwable into an array of ThrowableDataPoint objects.
20   * 
21   * 
22   * @author Ceki Gülcü
23   */
24  public class ThrowableProxyUtil {
25  
26    public static final int REGULAR_EXCEPTION_INDENT = 1;
27    public static final int SUPPRESSED_EXCEPTION_INDENT = 2;
28  
29    public static void build(ThrowableProxy nestedTP, Throwable nestedThrowable,
30        ThrowableProxy parentTP) {
31  
32      StackTraceElement[] nestedSTE = nestedThrowable.getStackTrace();
33  
34      int commonFramesCount = -1;
35      if (parentTP != null) {
36        commonFramesCount = findNumberOfCommonFrames(nestedSTE, parentTP
37            .getStackTraceElementProxyArray());
38      }
39  
40      nestedTP.commonFrames = commonFramesCount;
41      nestedTP.stackTraceElementProxyArray = steArrayToStepArray(nestedSTE);
42    }
43  
44    static StackTraceElementProxy[] steArrayToStepArray(StackTraceElement[] stea) {
45      if(stea == null) {
46        return new StackTraceElementProxy[0];
47      }
48      StackTraceElementProxy[] stepa = new StackTraceElementProxy[stea.length];
49      for (int i = 0; i < stepa.length; i++) {
50        stepa[i] = new StackTraceElementProxy(stea[i]);
51      }
52      return stepa;
53    }
54  
55    static int findNumberOfCommonFrames(StackTraceElement[] steArray,
56        StackTraceElementProxy[] parentSTEPArray) {
57      if (parentSTEPArray == null || steArray == null) {
58        return 0;
59      }
60  
61      int steIndex = steArray.length - 1;
62      int parentIndex = parentSTEPArray.length - 1;
63      int count = 0;
64      while (steIndex >= 0 && parentIndex >= 0) {
65        StackTraceElement ste = steArray[steIndex];
66        StackTraceElement otherSte = parentSTEPArray[parentIndex].ste;
67        if (ste.equals(otherSte)) {
68          count++;
69        } else {
70          break;
71        }
72        steIndex--;
73        parentIndex--;
74      }
75      return count;
76    }
77  
78    public static String asString(IThrowableProxy tp) {
79      StringBuilder sb = new StringBuilder();
80  
81      recursiveAppend(sb, null, REGULAR_EXCEPTION_INDENT, tp);
82  
83      return sb.toString();
84    }
85  
86    private static void recursiveAppend(StringBuilder sb, String prefix, int indent, IThrowableProxy tp) {
87      if(tp == null)
88        return;
89      subjoinFirstLine(sb, prefix, tp);
90      sb.append(CoreConstants.LINE_SEPARATOR);
91      subjoinSTEPArray(sb, indent, tp);
92      IThrowableProxy[] suppressed = tp.getSuppressed();
93      if(suppressed != null) {
94        for(IThrowableProxy current : suppressed) {
95          recursiveAppend(sb, CoreConstants.SUPPRESSED, SUPPRESSED_EXCEPTION_INDENT, current);
96        }
97      }
98      recursiveAppend(sb, CoreConstants.CAUSED_BY, REGULAR_EXCEPTION_INDENT, tp.getCause());
99    }
100 
101   private static void subjoinFirstLine(StringBuilder buf, String prefix, IThrowableProxy tp) {
102     if (prefix != null) {
103       buf.append(prefix);
104     }
105     subjoinExceptionMessage(buf, tp);
106   }
107 
108   public static void subjoinPackagingData(StringBuilder builder, StackTraceElementProxy step) {
109     if (step != null) {
110       ClassPackagingData cpd = step.getClassPackagingData();
111       if (cpd != null) {
112         if (!cpd.isExact()) {
113           builder.append(" ~[");
114         } else {
115           builder.append(" [");
116         }
117    
118         builder.append(cpd.getCodeLocation()).append(':').append(
119             cpd.getVersion()).append(']');
120       }
121     }
122   }
123   
124   public static void subjoinSTEP(StringBuilder sb, StackTraceElementProxy step) {
125     sb.append(step.toString());
126     subjoinPackagingData(sb, step);
127   }
128 
129   /**
130    * @param sb The StringBuilder the STEPs are appended to.
131    * @param tp the IThrowableProxy containing the STEPs.
132    * @deprecated Use subjoinSTEPArray(StringBuilder sb, int indentLevel, IThrowableProxy tp) instead.
133    */
134   public static void subjoinSTEPArray(StringBuilder sb, IThrowableProxy tp) {
135     // not called anymore - but it is public
136     subjoinSTEPArray(sb, REGULAR_EXCEPTION_INDENT, tp);
137   }
138 
139   /**
140    * @param sb The StringBuilder the STEPs are appended to.
141    * @param indentLevel indentation level used for the STEPs, usually either REGULAR_EXCEPTION_INDENT or SUPPRESSED_EXCEPTION_INDENT.
142    * @param tp the IThrowableProxy containing the STEPs.
143    */
144   public static void subjoinSTEPArray(StringBuilder sb, int indentLevel, IThrowableProxy tp) {
145     StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray();
146     int commonFrames = tp.getCommonFrames();
147 
148     for (int i = 0; i < stepArray.length - commonFrames; i++) {
149       StackTraceElementProxy step = stepArray[i];
150       for(int j = 0; j < indentLevel ; j++) {
151         sb.append(CoreConstants.TAB);
152       }
153       subjoinSTEP(sb, step);
154       sb.append(CoreConstants.LINE_SEPARATOR);
155     }
156     
157     if (commonFrames > 0) {
158       for(int j = 0; j < indentLevel ; j++) {
159         sb.append(CoreConstants.TAB);
160       }
161       sb.append("... ").append(commonFrames).append(" common frames omitted")
162           .append(CoreConstants.LINE_SEPARATOR);
163     }
164     
165   }
166 
167   public static void subjoinFirstLine(StringBuilder buf, IThrowableProxy tp) {
168     int commonFrames = tp.getCommonFrames();
169     if (commonFrames > 0) {
170       buf.append(CoreConstants.CAUSED_BY);
171     }
172     subjoinExceptionMessage(buf, tp);
173   }
174 
175   public static void subjoinFirstLineRootCauseFirst(StringBuilder buf, IThrowableProxy tp) {
176     if (tp.getCause() != null) {
177       buf.append(CoreConstants.WRAPPED_BY);
178     }
179     subjoinExceptionMessage(buf, tp);
180   }
181 
182   private static void subjoinExceptionMessage(StringBuilder buf, IThrowableProxy tp) {
183     buf.append(tp.getClassName()).append(": ").append(tp.getMessage());
184   }
185 }