blob: 774824757c4afa1313b9fb0f0abae19118672632 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sqoop.json;
import org.apache.sqoop.classification.InterfaceAudience;
import org.apache.sqoop.classification.InterfaceStability;
import org.apache.sqoop.common.SqoopException;
import org.apache.sqoop.utils.ClassUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.util.LinkedList;
import java.util.List;
/**
* Transfer throwable instance as a throwable bean.
*/
@InterfaceAudience.Private
@InterfaceStability.Unstable
public class ThrowableBean implements JsonBean {
public static final String MESSAGE = "message";
public static final String STACK_TRACE = "stack-trace";
public static final String CLASS = "class";
public static final String METHOD = "method";
public static final String FILE = "file";
public static final String LINE = "line";
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;
// For "extract"
public ThrowableBean(Throwable ex) {
throwable = ex;
}
// For "restore"
public ThrowableBean() {
}
public Throwable getThrowable() {
return throwable;
}
@Override
@SuppressWarnings("unchecked")
public JSONObject extract(boolean skipSensitive) {
JSONObject result = new JSONObject();
result.put(MESSAGE, throwable.getMessage());
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();
for(StackTraceElement element : throwable.getStackTrace()) {
JSONObject obj = new JSONObject();
obj.put(CLASS, element.getClassName());
obj.put(METHOD, element.getMethodName());
obj.put(FILE, element.getFileName());
obj.put(LINE, element.getLineNumber());
st.add(obj);
}
result.put(STACK_TRACE, st);
Throwable cause = throwable.getCause();
if(cause != null) {
ThrowableBean causeBean = new ThrowableBean(cause);
result.put(CAUSE, causeBean.extract(skipSensitive));
}
return result;
}
@Override
public void restore(JSONObject jsonObject) {
String exceptionClass = (String) jsonObject.get(CLASS);
String message = (String) jsonObject.get(MESSAGE);
if(message == null) {
message = "";
}
// Special handling for SqoopException as we need to transfer ERROR_CODE from the other side
if(jsonObject.containsKey(ERROR_CODE_CLASS)) {
Class e = ClassUtils.loadClass((String) jsonObject.get(ERROR_CODE_CLASS));
// 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) {
throwable = new Throwable(message);
}
List<StackTraceElement> st = new LinkedList<StackTraceElement>();
for(Object object : (JSONArray)jsonObject.get(STACK_TRACE)) {
JSONObject json = (JSONObject)object;
StackTraceElement element = new StackTraceElement(
(String)json.get(CLASS),
(String)json.get(METHOD),
(String)json.get(FILE),
((Long)json.get(LINE)).intValue()
);
st.add(element);
}
throwable.setStackTrace(st.toArray(new StackTraceElement[]{}));
Object cause = jsonObject.get(CAUSE);
if(cause != null) {
JSONObject causeJson = (JSONObject)cause;
ThrowableBean causeBean = new ThrowableBean();
causeBean.restore(causeJson);
throwable.initCause(causeBean.getThrowable());
}
}
}