JAL-3026 srcjar files for VARNA and log4j
[jalview.git] / srcjar / org / apache / log4j / EnhancedThrowableRenderer.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.apache.log4j;
18
19 import org.apache.log4j.spi.ThrowableRenderer;
20
21 import java.io.File;
22 import java.lang.reflect.Method;
23 import java.net.URL;
24 import java.security.CodeSource;
25 import java.util.HashMap;
26 import java.util.Map;
27
28 /**
29  * Enhanced implementation of ThrowableRenderer.  Uses Throwable.getStackTrace
30  * if running on JDK 1.4 or later and delegates to DefaultThrowableRenderer.render
31  * on earlier virtual machines.
32  *
33  * @since 1.2.16
34  */
35 public final class EnhancedThrowableRenderer implements ThrowableRenderer {
36     /**
37      * Throwable.getStackTrace() method.
38      */
39     private Method getStackTraceMethod;
40     /**
41      * StackTraceElement.getClassName() method.
42      */
43     private Method getClassNameMethod;
44
45
46     /**
47      * Construct new instance.
48      */
49     public EnhancedThrowableRenderer() {
50         try {
51             Class[] noArgs = null;
52             getStackTraceMethod = Throwable.class.getMethod("getStackTrace", noArgs);
53             Class ste = Class.forName("java.lang.StackTraceElement");
54             getClassNameMethod = ste.getMethod("getClassName", noArgs);
55         } catch(Exception ex) {
56         }
57     }
58
59     /**
60      * {@inheritDoc}
61      */
62     public String[] doRender(final Throwable throwable) {
63         if (getStackTraceMethod != null) {
64             try {
65                 Object[] noArgs = null;
66                 Object[] elements = (Object[]) getStackTraceMethod.invoke(throwable, noArgs);
67                 String[] lines = new String[elements.length + 1];
68                 lines[0] = throwable.toString();
69                 Map classMap = new HashMap();
70                 for(int i = 0; i < elements.length; i++) {
71                     lines[i+1] = formatElement(elements[i], classMap);
72                 }
73                 return lines;
74             } catch(Exception ex) {
75             }
76         }
77         return DefaultThrowableRenderer.render(throwable);
78     }
79
80     /**
81      * Format one element from stack trace.
82      * @param element element, may not be null.
83      * @param classMap map of class name to location.
84      * @return string representation of element.
85      */
86     private String formatElement(final Object element, final Map classMap) {
87         StringBuffer buf = new StringBuffer("\tat ");
88         buf.append(element);
89         try {
90             String className = getClassNameMethod.invoke(element, (Object[]) null).toString();
91             Object classDetails = classMap.get(className);
92             if (classDetails != null) {
93                 buf.append(classDetails);
94             } else {
95                 Class cls = findClass(className);
96                 int detailStart = buf.length();
97                 buf.append('[');
98                 try {
99                     CodeSource source = cls.getProtectionDomain().getCodeSource();
100                     if (source != null) {
101                         URL locationURL = source.getLocation();
102                         if (locationURL != null) {
103                             //
104                             //   if a file: URL
105                             //
106                             if ("file".equals(locationURL.getProtocol())) {
107                                 String path = locationURL.getPath();
108                                 if (path != null) {
109                                     //
110                                     //  find the last file separator character
111                                     //
112                                     int lastSlash = path.lastIndexOf('/');
113                                     int lastBack = path.lastIndexOf(File.separatorChar);
114                                     if (lastBack > lastSlash) {
115                                         lastSlash = lastBack;
116                                     }
117                                     //
118                                     //  if no separator or ends with separator (a directory)
119                                     //     then output the URL, otherwise just the file name.
120                                     //
121                                     if (lastSlash <= 0 || lastSlash == path.length() - 1) {
122                                         buf.append(locationURL);
123                                     } else {
124                                         buf.append(path.substring(lastSlash + 1));
125                                     }
126                                 }
127                             } else {
128                                 buf.append(locationURL);
129                             }
130                         }
131                     }
132                 } catch(SecurityException ex) {
133                 }
134                 buf.append(':');
135                 Package pkg = cls.getPackage();
136                 if (pkg != null) {
137                     String implVersion = pkg.getImplementationVersion();
138                     if (implVersion != null) {
139                         buf.append(implVersion);
140                     }
141                 }
142                 buf.append(']');
143                 classMap.put(className, buf.substring(detailStart));
144             }
145         } catch(Exception ex) {
146         }
147         return buf.toString();
148     }
149
150     /**
151      * Find class given class name.
152      * @param className class name, may not be null.
153      * @return class, will not be null.
154      * @throws ClassNotFoundException thrown if class can not be found.
155      */
156     private Class findClass(final String className) throws ClassNotFoundException {
157      try {
158        return Thread.currentThread().getContextClassLoader().loadClass(className);
159      } catch (ClassNotFoundException e) {
160        try {
161          return Class.forName(className);
162        } catch (ClassNotFoundException e1) {
163           return getClass().getClassLoader().loadClass(className);
164       }
165     }
166   }
167
168 }