View Javadoc

1   
2   package org.naftulin.classpathexplorer.stacktrace.impl;
3   
4   import java.io.File;
5   import java.io.PrintStream;
6   import java.io.PrintWriter;
7   import java.io.Serializable;
8   
9   import org.naftulin.classpathexplorer.resourceinfo.impl.ResourceInfo;
10  
11  
12  /***
13   * Combines stack element with resource information. The class is useful when
14   * it is needed to know which resource generates an exception. {@link #getExceptionDecorator} should
15   * be used to wrap the exception. When the wrapped exception is printed out,
16   * (for example to log file), each stack trace element will have resource information
17   * available in addition to the stack trace information.
18   * @author henry naftulin
19   * @version 1.0
20   */
21  public class StackTraceElementExtension implements Serializable {
22  	private static final long serialVersionUID = 1L;
23  	private static final StackTraceElementExtension[] EMPTY_TRACE = new StackTraceElementExtension[0];
24  	private final StackTraceElement stackTraceElement;
25  	private final ResourceInfo resourceInfo;
26  	
27  	/***
28  	 * Creates a stack trace extension based on the stack trace element.
29  	 * @param element
30  	 */
31  	public StackTraceElementExtension(StackTraceElement element) {
32  		this.stackTraceElement = element;
33  		Class clazz = null;
34  		ResourceInfo re = null;
35  		if (element.getClassName() != null) {
36  				try {
37  					clazz = Class.forName(element.getClassName());
38  					re = ResourceInfo.getResourceInfo(clazz);
39  				} catch (ClassNotFoundException e) {
40  					re = ResourceInfo.NOT_FOUND_RESOURCE_INFO;
41  				}
42  		}
43  		resourceInfo = re;
44  	}
45  
46  	/***
47  	 * Returns the file for archive for the class that this instance of the stack trace is describing.
48  	 * The file could be null, for example, if resource is not found.
49  	 * @return the file for archive for the class that this instance of the stack trace is describing.
50  	 */
51  	public File getClassArchiveSource() {
52  		return resourceInfo.getClassArchiveSource();
53  	}
54  
55  	/***
56  	 * Returns the stack trace element.
57  	 * @return the stack trace element
58  	 */
59  	public StackTraceElement getStackTraceElement() {
60  		return stackTraceElement;
61  	}
62  	
63  	/***
64  	 * Returns true if the class described in this stack trace is loaded from directory.
65  	 * Otherwise, the class described in this stack trace could not be found, or is loaded
66  	 * from and archive (e.g. zip or jar).
67  	 * @return true if the class described in this stack trace is loaded from directory.
68  	 */
69  	public boolean isDirectory() { 
70  		return getClassArchiveSource() != null && getClassArchiveSource().isDirectory();
71  	}
72  	
73  	/***
74  	 * Returns the name of the archive the class resides in, or not found if class was not found.
75  	 * @return the name of the archive the class resides in, or not found if class was not found.
76  	 */
77  	public String getArchiveName() {
78  		return getClassArchiveSource() != null ? getClassArchiveSource().getAbsolutePath() : "Not found";
79  	}
80  	
81  	public String toString() {
82  		StringBuffer sb = new StringBuffer(20);
83  		sb.append(stackTraceElement.toString());			
84  		if (this.resourceInfo != ResourceInfo.NOT_FOUND_RESOURCE_INFO) {
85  			sb.append(" [ from ");
86  			sb.append(getArchiveName());
87  			sb.append(isDirectory() ? " directory" : " archive");
88  			sb.append("] ");
89  		}
90  				
91  		return sb.toString();
92  	}
93  	
94  	private static StackTraceElementExtension[] covnverStackTrace(StackTraceElement[] elements) {
95  		if (elements == null) return EMPTY_TRACE;
96  		StackTraceElementExtension[] extensions = new StackTraceElementExtension[elements.length];
97  		for(int i=0; i < extensions.length; ++i) {
98  			extensions[i] = new StackTraceElementExtension(elements[i]);
99  		}
100 		return extensions;
101 	}
102 	
103 	/***
104 	 * Returns exception that the stack trace with additional resource information.
105 	 * @exception exception that will be decorated, resorce infomation will be added.
106 	 * @return exception with additional stack trace information.
107 	 */
108 	public static Exception getExceptionDecorator(Exception e) {
109 		return new StackTraceElementExtension.ExceptionDecorator(e);
110 	}
111 	
112 	/***
113 	 * Decorates exception with resource information for each of the stack traces.
114 	 * Follows GOF decorator pattern.
115 	 * @author henry naftulin
116 	 * @version 1.0
117 	 */
118 	static class ExceptionDecorator extends Exception implements Serializable {
119 		private static final long serialVersionUID = 1L;
120 		final Exception e;
121 		final StackTraceElementExtension[] elements;
122 		public ExceptionDecorator(Exception e) {
123 			super(e.getLocalizedMessage());
124 			this.e = e;
125 			elements = covnverStackTrace(e.getStackTrace());
126 		}
127 		
128 		public String getMessage() {return e.getMessage(); }
129 		public Throwable getCause() { return e.getCause(); }
130 		public String getLocalizedMessage() { return e.getLocalizedMessage(); }
131 		public Throwable initCause(Throwable cause) { return e.initCause(cause); }
132 		public void printStackTrace() { printStackTrace(System.err); }
133 		public void printStackTrace(PrintStream stream) {
134 			stream.print(e.getClass().getName());
135 			stream.print(" ");
136 			if (e.getLocalizedMessage() != null) {
137 				stream.print(e.getLocalizedMessage());
138 			}
139 			stream.println();
140 			for(int i=0; i < elements.length; ++i) {
141 				stream.print("\tat ");
142 				stream.println(elements[i].toString());
143 			}
144 			if (e.getCause() != null && e.getCause() != e ) {
145 				stream.print("Caused by: ");
146 				e.getCause().printStackTrace(stream);
147 			} 			
148 		}
149 		
150 		public void printStackTrace(PrintWriter writer) { 
151 			writer.print(e.getClass().getName());
152 			writer.print(" ");
153 			if (e.getLocalizedMessage() != null) {
154 				writer.print(e.getLocalizedMessage());
155 			}
156 			writer.println();
157 			for(int i=0; i < elements.length; ++i) {
158 				writer.print("\tat ");
159 				writer.println(elements[i].toString());
160 			}
161 			if (e.getCause() != null && e.getCause() != e ) {
162 				writer.print("Caused by: ");
163 				e.getCause().printStackTrace(writer);
164 			}  
165 			
166 		}
167 		public void setStackTrace(StackTraceElement[] trace) { e.setStackTrace(trace); }
168 		public Throwable fillInStackTrace() { return e != null ? e.fillInStackTrace() : null; }
169 	}
170 }