package net.sf.crispy;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.sf.crispy.impl.ServiceManager;
import net.sf.crispy.util.Converter;
import net.sf.crispy.util.Util;
/**
* Wraped the server side thrown exception. Transport to the client.
* Unwraped the exception and thrown the exception on the client side.
*
* @author Linke
* @since 1.1.0
*
*/
public final class ExceptionWrapper implements Serializable {
private static final long serialVersionUID = -2137246018098063392L;
private byte stackTraceByteArray[] = null;
private String message = "no message available";
private String exceptionClassName = "no exception class name";
private List stackTraceElementWrapperList = new ArrayList(0);
private Object exceptionPlaceHolder = null;
private boolean withExceptionSerializer = false;
public ExceptionWrapper() {}
public ExceptionWrapper(Throwable pvThrowable) {
this(pvThrowable, false);
}
public ExceptionWrapper(Throwable pvThrowable, boolean pvWithExceptionSerializer) {
setMessage(pvThrowable.getMessage());
setExceptionClassName(pvThrowable.getClass().getName());
stackTrace2ByteArray(pvThrowable);
copyStackTraceElement(pvThrowable.getStackTrace());
withExceptionSerializer = pvWithExceptionSerializer;
if (getWithExceptionSerializer() == true) {
createPlaceHolder(pvThrowable);
}
}
private void createPlaceHolder(Throwable pvThrowable) {
try {
Converter lvConverter = new Converter();
lvConverter.setWithSimpleKeyMapper(true);
exceptionPlaceHolder = lvConverter.makeSimple(pvThrowable);
// StackTrace can't unmarshall
((Map) exceptionPlaceHolder).remove("stackTrace");
} catch (Exception e) {
if (ServiceManager.DEBUG_MODE_ON) {
e.printStackTrace();
}
}
}
public boolean getWithExceptionSerializer() { return withExceptionSerializer; }
public void setExceptionPlaceHolder(Object pvPlaceHolder) { exceptionPlaceHolder = pvPlaceHolder; }
public Object getExceptionPlaceHolder() { return exceptionPlaceHolder; }
public void setMessage(String pvMessage) { message = pvMessage; }
public String getMessage() { return message; }
public void setExceptionClassName(String pvExceptionClassName) { exceptionClassName = pvExceptionClassName; }
public String getExceptionClassName() { return exceptionClassName; }
public void setStackTraceByteArray(byte b[]) { stackTraceByteArray = b; }
public byte[] getStackTraceByteArray() { return stackTraceByteArray; }
public List getStackTraceElementWrapperList() { return stackTraceElementWrapperList; }
public void setStackTraceElementWrapperList(List pvStackTraceElementWrapperList) {stackTraceElementWrapperList = pvStackTraceElementWrapperList;}
public void copyStackTraceElement(StackTraceElement[] pvStackTraceElements) {
int lvArraySize = pvStackTraceElements.length;
stackTraceElementWrapperList = new ArrayList(lvArraySize);
for (int i=0; i<lvArraySize; i++) {
stackTraceElementWrapperList.add(new StackTraceElementWrapper(pvStackTraceElements[i]));
}
}
public void stackTrace2ByteArray(Throwable pvThrowable) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream lvPrintStream = new PrintStream(out);
pvThrowable.printStackTrace(lvPrintStream);
setStackTraceByteArray(out.toByteArray());
}
public void printStackTrace2() {
int lvSize = stackTraceElementWrapperList.size();
System.out.println(getExceptionClassName() + ": " + getMessage());
for (int i=0; i<lvSize; i++) {
System.out.println(" at " + stackTraceElementWrapperList.get(i));
}
}
public void printStackTrace() {
printStackTrace(System.out);
}
public void printStackTrace(OutputStream pvOutputStream) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
out.write(getStackTraceByteArray());
out.writeTo(pvOutputStream);
out.flush();
out.close();
} catch (IOException e) {
if (ServiceManager.DEBUG_MODE_ON) {
e.printStackTrace();
}
}
}
public Exception newExceptionInstance() {
Exception lvResult = null;
try {
Converter lvConverter = new Converter();
lvConverter.setWithSimpleKeyMapper(true);
lvResult = (Exception) lvConverter.makeComplex(getExceptionPlaceHolder());
} catch (Exception e) {
if (ServiceManager.DEBUG_MODE_ON) {
e.printStackTrace();
}
}
if (lvResult != null) {
lvResult.initCause(new InvocationException(getMessage()));
return lvResult;
} else {
return newExceptionInstanceIntern();
}
}
private Exception newExceptionInstanceIntern() {
Exception lvException = new InvocationException(this);
try {
Class c = Class.forName(this.getExceptionClassName());
Constructor con[] = c.getConstructors();
for (int i = 0; i < con.length; i++) {
int lvParamSize = con[i].getParameterTypes().length;
if ((lvParamSize == 1) && (con[i].getParameterTypes()[0].equals(String.class))) {
lvException = (Exception) con[i].newInstance(new Object [] { this.getMessage() });
break;
}
else if (lvParamSize == 0) {
lvException = (Exception) con[i].newInstance(null);
break;
}
}
} catch (Exception e) {
if (ServiceManager.DEBUG_MODE_ON) {
e.printStackTrace();
}
}
return lvException;
}
/**
* This method is used on the server side (from the invocation handler) to convert the
* <code>Exception</code> to the <code>ExceptionWrapper</code>.
*
* @param pvResult Result of execution remote call (on the server side).
* @return The unchanged result object or if the result object is a Throwable,
* than is the return value a ExceptionWrapper from the Throwable.
*/
public static Object isThrowableThanHandleThrowable(final Object pvResult) {
if (pvResult instanceof Throwable) {
Throwable lvThrowable = (Throwable) pvResult;
if (ServiceManager.DEBUG_MODE_ON == true) {
lvThrowable.printStackTrace();
}
Throwable t = Util.findDeepestThrowable(lvThrowable);
return new ExceptionWrapper(t, true);
} else {
return pvResult;
}
}
/**
* This method is calling from the client side procy (Executor or Static-Proxy).
* It is converting from the <code>ExceptionWrapper</code> to the <code>Exception</code>.
*
* @param pvResult Result of execution remote call (on the server side).
* @return The same result object (unchanged)
* @throws Exception If the result is a map and in the map is a key: class and value
* is equals ExceptionWrapper, than throw the server side created Exception.
*/
public static Object isResultExceptionThanThrowIt (final Object pvResult) throws Exception {
if (pvResult instanceof Map) {
Map lvMap = (Map) pvResult;
Object lvClassObj = lvMap.get("class");
if ((lvClassObj != null) && lvClassObj.equals(ExceptionWrapper.class.getName())) {
// Map lvMapSimpleException = (Map) lvMap.get("simpleException");
// if (lvMapSimpleException != null) {
// lvMapSimpleException.remove("stackTrace");
// }
Converter lvConverter = new Converter();
lvConverter.setWithSimpleKeyMapper(true);
Object o = lvConverter.makeComplex(lvMap);
ExceptionWrapper lvExceptionWrapper = (ExceptionWrapper) o;
throw lvExceptionWrapper.newExceptionInstance();
}
}
else if (pvResult instanceof ExceptionWrapper) {
ExceptionWrapper lvExceptionWrapper = (ExceptionWrapper) pvResult;
throw lvExceptionWrapper.newExceptionInstance();
}
return pvResult;
}
}
|