SafetyMutex and rocket optimization updates
[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          * Get the description of the code position as provided in the constructor.
78          */
79         @Override
80         public String getMessage() {
81                 if (message == null) {
82                         StackTraceElement[] elements = this.getStackTrace();
83                         
84                         StringBuilder sb = new StringBuilder();
85                         if (minLevel < elements.length) {
86                                 
87                                 sb.append("(");
88                                 sb.append(toString(elements[minLevel]));
89                                 for (int i = minLevel + 1; i <= maxLevel; i++) {
90                                         if (i < elements.length) {
91                                                 sb.append(' ').append(toString(elements[i]));
92                                         }
93                                 }
94                                 sb.append(')');
95                                 
96                         } else if (elements.length == 0) {
97                                 
98                                 sb.append("(no stack trace)");
99                                 
100                         } else {
101                                 
102                                 sb.append('(');
103                                 sb.append(toString(elements[0]));
104                                 for (int i = 1; i < elements.length; i++) {
105                                         sb.append(' ').append(toString(elements[i]));
106                                 }
107                                 sb.append(" level=").append(minLevel).append(')');
108                                 
109                         }
110                         message = sb.toString();
111                 }
112                 return message;
113         }
114         
115         
116         private static String toString(StackTraceElement element) {
117                 if (element.getClassName().startsWith(STANDARD_PACKAGE_PREFIX)) {
118                         return element.getFileName() + ":" + element.getLineNumber();
119                 } else {
120                         return element.toString();
121                 }
122         }
123         
124 }