All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.stackify.api.common.lang.Throwables Maven / Gradle / Ivy

There is a newer version: 4.0.3
Show newest version
/*
 * Copyright 2013 Stackify
 *
 * 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 com.stackify.api.common.lang;

import java.util.ArrayList;
import java.util.List;

import com.stackify.api.ErrorItem;
import com.stackify.api.TraceFrame;

/**
 * Utility class for converting a Throwable object to an ErrorItem object
 * 
 * @author Eric Martin
 */
public class Throwables {

	/**
	 * Returns the Throwable's cause chain as a list. The first entry is the Throwable followed by the cause chain.
	 * @param throwable The Throwable
	 * @return The Throwable and its cause chain
	 */
	public static List getCausalChain(final Throwable throwable) {
		if (throwable == null) {
			throw new NullPointerException("Throwable is null");
		}
		
		List causes = new ArrayList();
		causes.add(throwable);
		
		Throwable cause = throwable.getCause();
		
		while ((cause != null) && (!causes.contains(cause))) {
			causes.add(cause);
			cause = cause.getCause();
		}
		
		return causes;
	}
	
	/**
	 * Converts a Throwable to an ErrorItem
	 * @param logMessage The log message (can be null)
	 * @param t The Throwable to be converted
	 * @return The ErrorItem
	 */
	public static ErrorItem toErrorItem(final String logMessage, final Throwable t) {
		
		// get a flat list of the throwable and the causal chain
		
		List throwables = Throwables.getCausalChain(t);

		// create and populate builders for all throwables
		
		List builders = new ArrayList(throwables.size());
		
		for (int i = 0; i < throwables.size(); ++i) {
			if (i == 0) {
				ErrorItem.Builder builder = toErrorItemBuilderWithoutCause(logMessage, throwables.get(i));
				builders.add(builder);
			} else {
				ErrorItem.Builder builder = toErrorItemBuilderWithoutCause(null, throwables.get(i));
				builders.add(builder);
			}
		}
		
		// attach child errors to their parent in reverse order
		
		for (int i = builders.size() - 1; 0 < i; --i) {
			ErrorItem.Builder parent = builders.get(i - 1);
			ErrorItem.Builder child = builders.get(i);
			
			parent.innerError(child.build());
		}
		
		// return the assembled original error
		
		return builders.get(0).build();
	}
	
	/**
	 * Converts a Throwable to an ErrorItem
	 * @param t The Throwable to be converted
	 * @return The ErrorItem
	 */
	public static ErrorItem toErrorItem(final Throwable t) {
		return toErrorItem(null, t);
	}
	
	/**
	 * Converts a Throwable to an ErrorItem.Builder and ignores the cause
	 * @param logMessage The log message
	 * @param t The Throwable to be converted
	 * @return The ErrorItem.Builder without the innerError populated
	 */
	private static ErrorItem.Builder toErrorItemBuilderWithoutCause(final String logMessage, final Throwable t) {
		ErrorItem.Builder builder = ErrorItem.newBuilder();
		builder.message(toErrorItemMessage(logMessage, t.getMessage()));
		builder.errorType(t.getClass().getCanonicalName());
		
		List stackFrames = new ArrayList();
		
		StackTraceElement[] stackTrace = t.getStackTrace();
		
		if ((stackTrace != null) && (0 < stackTrace.length)) {
			StackTraceElement firstFrame = stackTrace[0];
			builder.sourceMethod(firstFrame.getClassName() + "." + firstFrame.getMethodName());
			
			for (int i = 0; i < stackTrace.length; ++i) {
				TraceFrame stackFrame = StackTraceElements.toTraceFrame(stackTrace[i]);
				stackFrames.add(stackFrame);
			}
		}
		
		builder.stackTrace(stackFrames);
		
		return builder;
	}
	
	/**
	 * Constructs the error item message from the log message and the throwable's message
	 * @param logMessage The log message (can be null)
	 * @param throwableMessage The throwable's message (can be null)
	 * @return The error item message
	 */
	private static String toErrorItemMessage(final String logMessage, final String throwableMessage) {
		
		StringBuilder sb = new StringBuilder();
				
		if ((throwableMessage != null) && (!throwableMessage.isEmpty())) {
			sb.append(throwableMessage);
			
			if ((logMessage != null) && (!logMessage.isEmpty())) {
				sb.append(" (");
				sb.append(logMessage);
				sb.append(")");
			}			
		} else {
			sb.append(logMessage);
		}

		return sb.toString();
	}
	
	/**
	 * Create an error item from a simple log message (without an explicit exception)
	 * @param logMessage The log message
	 * @param className The class that logged the message
	 * @param methodName The method that logged the message
	 * @param lineNumber The line number that logged the message
	 * @return The error item
	 */
	public static ErrorItem toErrorItem(final String logMessage, final String className, final String methodName, final int lineNumber) {
		
		ErrorItem.Builder builder = ErrorItem.newBuilder();
		builder.message(logMessage);
		builder.errorType("StringException");
		builder.sourceMethod(className + "." + methodName);
		
		List stackFrames = new ArrayList();

		StackTraceElement[] stackTrace = (new Throwable()).getStackTrace();

		int start = 0;
		
		if ((className != null) && (methodName != null)) {
			for (int i = 0; i < stackTrace.length; ++i) {
				StackTraceElement ste = (stackTrace[i]);
				
				if (className.equals(ste.getClassName()) && 
				    methodName.equals(ste.getMethodName()) && 
				    lineNumber == ste.getLineNumber()) {
					start = i;
					break;
				}
			}
		}
		
		for (int i = start; i < stackTrace.length; ++i) {
			TraceFrame stackFrame = StackTraceElements.toTraceFrame(stackTrace[i]);
			stackFrames.add(stackFrame);
		}

		builder.stackTrace(stackFrames);
		
		return builder.build();
	}
	
	/**
	 * Hidden to prevent construction
	 */
	private Throwables() {
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy