5
0
mirror of https://github.com/apache/sqoop.git synced 2025-05-10 04:50:29 +08:00

SQOOP-1426: Sqoop2: ThrowableBean should correct reconstruct SqoopException

This commit is contained in:
Jarek Jarcec Cecho 2014-08-11 17:40:04 -07:00 committed by Abraham Elmahrek
parent cf448a2291
commit 199d342df7
3 changed files with 89 additions and 30 deletions

View File

@ -28,28 +28,37 @@
public class SqoopException extends RuntimeException { public class SqoopException extends RuntimeException {
private final ErrorCode code; private final ErrorCode code;
private final String originalMessage;
public SqoopException(ErrorCode code) { public SqoopException(ErrorCode code) {
super(code.getCode() + ":" + code.getMessage()); super(code.getCode() + ":" + code.getMessage());
this.code = code; this.code = code;
originalMessage = null;
} }
public SqoopException(ErrorCode code, String extraInfo) { public SqoopException(ErrorCode code, String extraInfo) {
super(code.getCode() + ":" + code.getMessage() + " - " + extraInfo); super(code.getCode() + ":" + code.getMessage() + " - " + extraInfo);
this.code = code; this.code = code;
originalMessage = extraInfo;
} }
public SqoopException(ErrorCode code, Throwable cause) { public SqoopException(ErrorCode code, Throwable cause) {
super(code.getCode() + ":" + code.getMessage(), cause); super(code.getCode() + ":" + code.getMessage(), cause);
this.code = code; this.code = code;
originalMessage = null;
} }
public SqoopException(ErrorCode code, String extraInfo, Throwable cause) { public SqoopException(ErrorCode code, String extraInfo, Throwable cause) {
super(code.getCode() + ":" + code.getMessage() + " - " + extraInfo, cause); super(code.getCode() + ":" + code.getMessage() + " - " + extraInfo, cause);
this.code = code; this.code = code;
originalMessage = extraInfo;
} }
public ErrorCode getErrorCode() { public ErrorCode getErrorCode() {
return code; return code;
} }
public String getOriginalMessage() {
return originalMessage;
}
} }

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.sqoop.json; package org.apache.sqoop.json;
import org.apache.sqoop.common.SqoopException;
import org.apache.sqoop.utils.ClassUtils; import org.apache.sqoop.utils.ClassUtils;
import org.json.simple.JSONArray; import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
@ -36,6 +37,8 @@ public class ThrowableBean implements JsonBean {
public static final String FILE = "file"; public static final String FILE = "file";
public static final String LINE = "line"; public static final String LINE = "line";
public static final String CAUSE = "cause"; public static final String CAUSE = "cause";
public static final String ERROR_CODE = "error-code";
public static final String ERROR_CODE_CLASS = "error-code-class";
private Throwable throwable; private Throwable throwable;
@ -60,6 +63,14 @@ public JSONObject extract(boolean skipSensitive) {
result.put(MESSAGE, throwable.getMessage()); result.put(MESSAGE, throwable.getMessage());
result.put(CLASS, throwable.getClass().getName()); result.put(CLASS, throwable.getClass().getName());
if(throwable instanceof SqoopException ) {
SqoopException sqoopException = (SqoopException) throwable;
result.put(ERROR_CODE, sqoopException.getErrorCode().getCode());
result.put(ERROR_CODE_CLASS, sqoopException.getErrorCode().getClass().getName());
// Override message with the original message
result.put(MESSAGE, sqoopException.getOriginalMessage());
}
JSONArray st = new JSONArray(); JSONArray st = new JSONArray();
for(StackTraceElement element : throwable.getStackTrace()) { for(StackTraceElement element : throwable.getStackTrace()) {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
@ -91,11 +102,25 @@ public void restore(JSONObject jsonObject) {
message = ""; message = "";
} }
// Let's firstly try to instantiate same class that was originally on remote // Special handling for SqoopException as we need to transfer ERROR_CODE from the other side
// side. Fallback to generic Throwable in case that this particular if(jsonObject.containsKey(ERROR_CODE_CLASS)) {
// exception is not known to this JVM (for example during server-client Class e = ClassUtils.loadClass((String) jsonObject.get(ERROR_CODE_CLASS));
// exchange).
throwable = (Throwable) ClassUtils.instantiate(exceptionClass, message); // Only if the error code class is known to this JVM, let's instantiate the real SqoopException
if( e != null) {
String errorCode = (String) jsonObject.get(ERROR_CODE);
Enum enumValue = Enum.valueOf(e, errorCode);
throwable = (Throwable) ClassUtils.instantiate(exceptionClass, enumValue, message);
}
}
// Let's try to instantiate same class that was originally on remote side.
if(throwable == null) {
throwable = (Throwable) ClassUtils.instantiate(exceptionClass, message);
}
// Fallback to generic Throwable in case that this particular exception is not known
// to this JVM (for example during server-client exchange).
if(throwable == null) { if(throwable == null) {
throwable = new Throwable(message); throwable = new Throwable(message);
} }

View File

@ -17,35 +17,60 @@
*/ */
package org.apache.sqoop.json; package org.apache.sqoop.json;
import junit.framework.TestCase; import org.apache.sqoop.common.SqoopException;
import org.apache.sqoop.json.util.SerializationError;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.json.simple.JSONValue; import org.json.simple.JSONValue;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/** /**
* *
*/ */
public class TestThrowableBean extends TestCase { public class TestThrowableBean {
// public void testSerialization() {
// Throwable ex = new RuntimeException("A"); @Test
// ex.initCause(new Exception("B")); public void testSerialization() {
// Throwable ex = new RuntimeException("A");
// // Serialize it to JSON object ex.initCause(new Exception("B"));
// ThrowableBean bean = new ThrowableBean(ex);
// JSONObject json = bean.extract(false); Throwable retrieved = transfer(ex);
//
// // "Move" it across network in text form assertEquals("A", retrieved.getMessage());
// String string = json.toJSONString(); assertEquals(RuntimeException.class, retrieved.getClass());
// assertEquals("B", retrieved.getCause().getMessage());
// // Retrieved transferred object assertEquals(Exception.class, retrieved.getCause().getClass());
// JSONObject retrievedJson = (JSONObject) JSONValue.parse(string); assertNull(retrieved.getCause().getCause());
// ThrowableBean retrievedBean = new ThrowableBean(); }
// retrievedBean.restore(retrievedJson);
// Throwable retrieved = retrievedBean.getThrowable(); @Test
// public void testSqoopException() {
// assertEquals("A", retrieved.getMessage()); SqoopException ex = new SqoopException(SerializationError.SERIALIZATION_001, "Secret");
// assertEquals(RuntimeException.class, retrieved.getClass()); Throwable retrieved = transfer(ex);
// assertEquals("B", retrieved.getCause().getMessage());
// assertEquals(Exception.class, retrieved.getCause().getClass()); assertNotNull(retrieved);
// assertNull(retrieved.getCause().getCause()); assertEquals(SqoopException.class, retrieved.getClass());
// } SqoopException sqoopRetrieved = (SqoopException) retrieved;
assertEquals(SerializationError.class, sqoopRetrieved.getErrorCode().getClass());
assertEquals(SerializationError.SERIALIZATION_001, sqoopRetrieved.getErrorCode());
assertEquals("SERIALIZATION_001:Attempt to pass a non-map object to MAP type. - Secret", sqoopRetrieved.getMessage());
}
public Throwable transfer(Throwable source) {
// Serialize it to JSON object
ThrowableBean bean = new ThrowableBean(source);
JSONObject json = bean.extract(false);
// "Move" it across network in text form
String string = json.toJSONString();
// Retrieved transferred object
JSONObject retrievedJson = (JSONObject) JSONValue.parse(string);
ThrowableBean retrievedBean = new ThrowableBean();
retrievedBean.restore(retrievedJson);
return retrievedBean.getThrowable();
}
} }