1 package net.sf.crispy;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.OutputStream;
6 import java.io.PrintStream;
7 import java.io.Serializable;
8 import java.lang.reflect.Constructor;
9 import java.util.ArrayList;
10 import java.util.List;
11 import java.util.Map;
12
13 import net.sf.crispy.impl.ServiceManager;
14 import net.sf.crispy.util.Converter;
15 import net.sf.crispy.util.Util;
16
17 /**
18 * Wraped the server side thrown exception. Transport to the client.
19 * Unwraped the exception and thrown the exception on the client side.
20 *
21 * @author Linke
22 * @since 1.1.0
23 *
24 */
25 public final class ExceptionWrapper implements Serializable {
26
27 private static final long serialVersionUID = -2137246018098063392L;
28
29 private byte stackTraceByteArray[] = null;
30 private String message = "no message available";
31 private String exceptionClassName = "no exception class name";
32 private List stackTraceElementWrapperList = new ArrayList(0);
33
34 private Object exceptionPlaceHolder = null;
35 private boolean withExceptionSerializer = false;
36
37 public ExceptionWrapper() {}
38
39 public ExceptionWrapper(Throwable pvThrowable) {
40 this(pvThrowable, false);
41 }
42 public ExceptionWrapper(Throwable pvThrowable, boolean pvWithExceptionSerializer) {
43 setMessage(pvThrowable.getMessage());
44 setExceptionClassName(pvThrowable.getClass().getName());
45 stackTrace2ByteArray(pvThrowable);
46 copyStackTraceElement(pvThrowable.getStackTrace());
47 withExceptionSerializer = pvWithExceptionSerializer;
48
49 if (getWithExceptionSerializer() == true) {
50 createPlaceHolder(pvThrowable);
51 }
52 }
53
54 private void createPlaceHolder(Throwable pvThrowable) {
55 try {
56 Converter lvConverter = new Converter();
57 lvConverter.setWithSimpleKeyMapper(true);
58 exceptionPlaceHolder = lvConverter.makeSimple(pvThrowable);
59
60 ((Map) exceptionPlaceHolder).remove("stackTrace");
61 } catch (Exception e) {
62 if (ServiceManager.DEBUG_MODE_ON) {
63 e.printStackTrace();
64 }
65 }
66 }
67
68 public boolean getWithExceptionSerializer() { return withExceptionSerializer; }
69
70 public void setExceptionPlaceHolder(Object pvPlaceHolder) { exceptionPlaceHolder = pvPlaceHolder; }
71 public Object getExceptionPlaceHolder() { return exceptionPlaceHolder; }
72
73 public void setMessage(String pvMessage) { message = pvMessage; }
74 public String getMessage() { return message; }
75
76 public void setExceptionClassName(String pvExceptionClassName) { exceptionClassName = pvExceptionClassName; }
77 public String getExceptionClassName() { return exceptionClassName; }
78
79 public void setStackTraceByteArray(byte b[]) { stackTraceByteArray = b; }
80 public byte[] getStackTraceByteArray() { return stackTraceByteArray; }
81
82 public List getStackTraceElementWrapperList() { return stackTraceElementWrapperList; }
83 public void setStackTraceElementWrapperList(List pvStackTraceElementWrapperList) {stackTraceElementWrapperList = pvStackTraceElementWrapperList;}
84
85 public void copyStackTraceElement(StackTraceElement[] pvStackTraceElements) {
86 int lvArraySize = pvStackTraceElements.length;
87 stackTraceElementWrapperList = new ArrayList(lvArraySize);
88 for (int i=0; i<lvArraySize; i++) {
89 stackTraceElementWrapperList.add(new StackTraceElementWrapper(pvStackTraceElements[i]));
90 }
91 }
92
93 public void stackTrace2ByteArray(Throwable pvThrowable) {
94 ByteArrayOutputStream out = new ByteArrayOutputStream();
95 PrintStream lvPrintStream = new PrintStream(out);
96 pvThrowable.printStackTrace(lvPrintStream);
97
98 setStackTraceByteArray(out.toByteArray());
99 }
100
101 public void printStackTrace2() {
102 int lvSize = stackTraceElementWrapperList.size();
103 System.out.println(getExceptionClassName() + ": " + getMessage());
104 for (int i=0; i<lvSize; i++) {
105 System.out.println(" at " + stackTraceElementWrapperList.get(i));
106 }
107 }
108
109 public void printStackTrace() {
110 printStackTrace(System.out);
111 }
112
113 public void printStackTrace(OutputStream pvOutputStream) {
114 ByteArrayOutputStream out = new ByteArrayOutputStream();
115 try {
116 out.write(getStackTraceByteArray());
117 out.writeTo(pvOutputStream);
118 out.flush();
119 out.close();
120 } catch (IOException e) {
121 if (ServiceManager.DEBUG_MODE_ON) {
122 e.printStackTrace();
123 }
124 }
125
126 }
127
128 public Exception newExceptionInstance() {
129
130 Exception lvResult = null;
131 try {
132 Converter lvConverter = new Converter();
133 lvConverter.setWithSimpleKeyMapper(true);
134 lvResult = (Exception) lvConverter.makeComplex(getExceptionPlaceHolder());
135 } catch (Exception e) {
136 if (ServiceManager.DEBUG_MODE_ON) {
137 e.printStackTrace();
138 }
139 }
140 if (lvResult != null) {
141 lvResult.initCause(new InvocationException(getMessage()));
142 return lvResult;
143 } else {
144 return newExceptionInstanceIntern();
145 }
146 }
147
148 private Exception newExceptionInstanceIntern() {
149 Exception lvException = new InvocationException(this);
150 try {
151 Class c = Class.forName(this.getExceptionClassName());
152 Constructor con[] = c.getConstructors();
153 for (int i = 0; i < con.length; i++) {
154 int lvParamSize = con[i].getParameterTypes().length;
155 if ((lvParamSize == 1) && (con[i].getParameterTypes()[0].equals(String.class))) {
156 lvException = (Exception) con[i].newInstance(new Object [] { this.getMessage() });
157 break;
158 }
159 else if (lvParamSize == 0) {
160 lvException = (Exception) con[i].newInstance(null);
161 break;
162 }
163 }
164 } catch (Exception e) {
165 if (ServiceManager.DEBUG_MODE_ON) {
166 e.printStackTrace();
167 }
168 }
169 return lvException;
170 }
171
172 /**
173 * This method is used on the server side (from the invocation handler) to convert the
174 * <code>Exception</code> to the <code>ExceptionWrapper</code>.
175 *
176 * @param pvResult Result of execution remote call (on the server side).
177 * @return The unchanged result object or if the result object is a Throwable,
178 * than is the return value a ExceptionWrapper from the Throwable.
179 */
180 public static Object isThrowableThanHandleThrowable(final Object pvResult) {
181 if (pvResult instanceof Throwable) {
182 Throwable lvThrowable = (Throwable) pvResult;
183
184 if (ServiceManager.DEBUG_MODE_ON == true) {
185 lvThrowable.printStackTrace();
186 }
187
188 Throwable t = Util.findDeepestThrowable(lvThrowable);
189 return new ExceptionWrapper(t, true);
190 } else {
191 return pvResult;
192 }
193 }
194
195 /**
196 * This method is calling from the client side procy (Executor or Static-Proxy).
197 * It is converting from the <code>ExceptionWrapper</code> to the <code>Exception</code>.
198 *
199 * @param pvResult Result of execution remote call (on the server side).
200 * @return The same result object (unchanged)
201 * @throws Exception If the result is a map and in the map is a key: class and value
202 * is equals ExceptionWrapper, than throw the server side created Exception.
203 */
204 public static Object isResultExceptionThanThrowIt (final Object pvResult) throws Exception {
205 if (pvResult instanceof Map) {
206 Map lvMap = (Map) pvResult;
207 Object lvClassObj = lvMap.get("class");
208 if ((lvClassObj != null) && lvClassObj.equals(ExceptionWrapper.class.getName())) {
209
210
211
212
213
214
215 Converter lvConverter = new Converter();
216 lvConverter.setWithSimpleKeyMapper(true);
217 Object o = lvConverter.makeComplex(lvMap);
218 ExceptionWrapper lvExceptionWrapper = (ExceptionWrapper) o;
219 throw lvExceptionWrapper.newExceptionInstance();
220 }
221 }
222 else if (pvResult instanceof ExceptionWrapper) {
223 ExceptionWrapper lvExceptionWrapper = (ExceptionWrapper) pvResult;
224 throw lvExceptionWrapper.newExceptionInstance();
225 }
226 return pvResult;
227 }
228
229 }