01029d7d34e06493b316b6f4c1e7ff5973ca4912
[debian/openrocket] / src / net / sf / openrocket / logging / TraceException.java
1 package net.sf.openrocket.logging;
2
3
4
5 /**
6  * An exception that is used to store a stack trace.  On modern computers
7  * instantiation of an exception takes on the order of one microsecond, while
8  * examining the trace typically takes several times longer.  Therefore the
9  * exception should be stored and the stack trace examined only when necessary.
10  * <p>
11  * The {@link #getMessage()} method returns a description of the position
12  * where this exception has been instantiated.  The position is provided
13  * as many levels upwards from the instantiation position as provided to the
14  * constructor.
15  * 
16  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
17  */
18 public class TraceException extends Exception {
19         
20         private static final String STANDARD_PACKAGE_PREFIX = "net.sf.openrocket.";
21         
22         private final int minLevel;
23         private final int maxLevel;
24         private volatile String message = null;
25         
26         
27         /**
28          * Instantiate exception that provides the line of instantiation as a message.
29          */
30         public TraceException() {
31                 this(0, 0);
32         }
33         
34         /**
35          * Instantiate exception that provides the provided number of levels upward
36          * from the instantiation location as a message.  The level provided 
37          * is how many levels upward should be examined to find the stack trace 
38          * position for the exception message.
39          * 
40          * @param level         how many levels upward to examine the stack trace to find
41          *                                      the correct message.
42          */
43         public TraceException(int level) {
44                 this(level, level);
45         }
46         
47         
48         /**
49          * Instantiate exception that provides a range of levels upward from the
50          * instantiation location as a message.  This is useful to identify the
51          * next level of callers upward.
52          * 
53          * @param minLevel      the first level which to include.
54          * @param maxLevel      the last level which to include.
55          */
56         public TraceException(int minLevel, int maxLevel) {
57                 if (minLevel > maxLevel || minLevel < 0) {
58                         throw new IllegalArgumentException("minLevel=" + minLevel + " maxLevel=" + maxLevel);
59                 }
60                 this.minLevel = minLevel;
61                 this.maxLevel = maxLevel;
62         }
63         
64         
65         /**
66          * Construct an exception with the specified message.
67          * 
68          * @param message       the message for the exception.
69          */
70         public TraceException(String message) {
71                 this(0, 0);
72                 this.message = message;
73         }
74         
75         
76         /**
77          * Construct an exception with the specified message and cause.
78          * 
79          * @param message       the message for the exception.
80          * @param cause         the cause for this exception.
81          */
82         public TraceException(String message, Throwable cause) {
83                 this(0, 0);
84                 this.message = message;
85                 this.initCause(cause);
86         }
87         
88         
89         /**
90          * Get the description of the code position as provided in the constructor.
91          */
92         @Override
93         public String getMessage() {
94                 if (message == null) {
95                         StackTraceElement[] elements = this.getStackTrace();
96                         
97                         StringBuilder sb = new StringBuilder();
98                         if (minLevel < elements.length) {
99                                 
100                                 sb.append("(");
101                                 sb.append(toString(elements[minLevel]));
102                                 for (int i = minLevel + 1; i <= maxLevel; i++) {
103                                         if (i < elements.length) {
104                                                 sb.append(' ').append(toString(elements[i]));
105                                         }
106                                 }
107                                 sb.append(')');
108                                 
109                         } else if (elements.length == 0) {
110                                 
111                                 sb.append("(no stack trace)");
112                                 
113                         } else {
114                                 
115                                 sb.append('(');
116                                 sb.append(toString(elements[0]));
117                                 for (int i = 1; i < elements.length; i++) {
118                                         sb.append(' ').append(toString(elements[i]));
119                                 }
120                                 sb.append(" level=").append(minLevel).append(')');
121                                 
122                         }
123                         message = sb.toString();
124                 }
125                 return message;
126         }
127         
128         
129         private static String toString(StackTraceElement element) {
130                 if (element.getClassName().startsWith(STANDARD_PACKAGE_PREFIX)) {
131                         return element.getFileName() + ":" + element.getLineNumber();
132                 } else {
133                         return element.toString();
134                 }
135         }
136         
137 }