package org.ehcache.clustered.common.internal.messages;
import org.ehcache.clustered.common.internal.exceptions.ClusterException;
import org.ehcache.clustered.common.internal.exceptions.UnknownClusterException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terracotta.runnel.Struct;
import org.terracotta.runnel.StructBuilder;
import org.terracotta.runnel.decoding.StructArrayDecoder;
import org.terracotta.runnel.decoding.StructDecoder;
import org.terracotta.runnel.encoding.StructArrayEncoder;
import org.terracotta.runnel.encoding.StructEncoder;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
final class ExceptionCodec {
private ExceptionCodec() {
}
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCodec.class);
private static final String DECLARING_CLASS_FIELD = "declaringClass";
private static final String METHOD_NAME_FIELD = "methodName";
private static final String FILE_NAME_FIELD = "fileName";
private static final String LINE_NUM_FIELD = "lineNumber";
private static final String FQCN_FIELD = "fqcn";
private static final String MESSAGE_FIELD = "message";
private static final String STACKTRACE_ELEMENTS_FIELD = "stacktraceElements";
private static final Struct STE_STRUCT = StructBuilder.newStructBuilder()
.string(DECLARING_CLASS_FIELD, 10)
.string(METHOD_NAME_FIELD, 20)
.string(FILE_NAME_FIELD, 30)
.int32(LINE_NUM_FIELD, 40)
.build();
static final Struct EXCEPTION_STRUCT = StructBuilder.newStructBuilder()
.string(FQCN_FIELD, 10)
.string(MESSAGE_FIELD, 20)
.structs(STACKTRACE_ELEMENTS_FIELD, 30, STE_STRUCT)
.build();
public static void encode(StructEncoder<?> encoder, ClusterException exception) {
encoder.string(FQCN_FIELD, exception.getClass().getCanonicalName());
encoder.string(MESSAGE_FIELD, exception.getMessage());
StructArrayEncoder<?> arrayEncoder = encoder.structs(STACKTRACE_ELEMENTS_FIELD);
for (StackTraceElement stackTraceElement : exception.getStackTrace()) {
StructEncoder<?> element = arrayEncoder.add();
element.string(DECLARING_CLASS_FIELD, stackTraceElement.getClassName());
element.string(METHOD_NAME_FIELD, stackTraceElement.getMethodName());
if (stackTraceElement.getFileName() != null) {
element.string(FILE_NAME_FIELD, stackTraceElement.getFileName());
}
element.int32(LINE_NUM_FIELD, stackTraceElement.getLineNumber());
element.end();
}
arrayEncoder.end();
}
public static ClusterException decode(StructDecoder<StructDecoder<Void>> decoder) {
String exceptionClassName = decoder.string(FQCN_FIELD);
String message = decoder.string(MESSAGE_FIELD);
StructArrayDecoder<StructDecoder<StructDecoder<Void>>> arrayDecoder = decoder.structs(STACKTRACE_ELEMENTS_FIELD);
StackTraceElement[] stackTraceElements = new StackTraceElement[arrayDecoder.length()];
for (int i = 0; i < arrayDecoder.length(); i++) {
StructDecoder<?> element = arrayDecoder.next();
stackTraceElements[i] = new StackTraceElement(
element.string(DECLARING_CLASS_FIELD),
element.string(METHOD_NAME_FIELD),
element.string(FILE_NAME_FIELD),
element.int32(LINE_NUM_FIELD));
element.end();
}
arrayDecoder.end();
Class<? extends ClusterException> clazz = null;
ClusterException exception;
try {
clazz = Class.forName(exceptionClassName).asSubclass(ClusterException.class);
} catch (ClassNotFoundException e) {
LOGGER.error("Exception type not found", e);
}
exception = getClusterException(message, clazz);
if (exception == null) {
exception = new UnknownClusterException(message);
}
exception.setStackTrace(stackTraceElements);
return exception;
}
@SuppressWarnings("unchecked")
private static ClusterException getClusterException(String message, Class<? extends ClusterException> clazz) {
ClusterException exception = null;
if (clazz != null) {
try {
Constructor<? extends ClusterException> declaredConstructor = clazz.getDeclaredConstructor(String.class);
exception = declaredConstructor.newInstance(message);
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
LOGGER.error("Failed to instantiate exception object.", e);
}
}
return exception;
}
}