/* * Copyright Terracotta, Inc. * * Licensed 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.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 org.terracotta.runnel.encoding.StructEncoderFunction; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; final class ExceptionCodec { private ExceptionCodec() { //no instances please } public static final StructEncoderFunction<ClusterException> EXCEPTION_ENCODER_FUNCTION = new StructEncoderFunction<ClusterException>() { @Override public void encode(StructEncoder<?> encoder, ClusterException exception) { ExceptionCodec.encode(encoder, exception); } }; 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 clazz = null; ClusterException exception = null; try { clazz = Class.forName(exceptionClassName); } 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 clazz) { ClusterException exception = null; if (clazz != null) { try { Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class); exception = (ClusterException)declaredConstructor.newInstance(message); } catch (NoSuchMethodException e) { LOGGER.error("Failed to instantiate exception object.", e); } catch (IllegalAccessException e) { LOGGER.error("Failed to instantiate exception object.", e); } catch (InstantiationException e) { LOGGER.error("Failed to instantiate exception object.", e); } catch (InvocationTargetException e) { LOGGER.error("Failed to instantiate exception object.", e); } } return exception; } }