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

com.aegisql.util.function.ExceptionHandler Maven / Gradle / Ivy

The newest version!
/*
 *Copyright (c) 2015, AEGIS DATA SOLUTIONS, All rights reserved. 
 */
package com.aegisql.util.function;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * The Class ExceptionHandler.
 * @author Mikhail Teplitskiy
 *
 * @param  the generic type
 */
public final class ExceptionHandler implements ExceptionBlock {
	
	/** The Constant log. */
	public static final Logger log = LoggerFactory.getLogger(ExceptionHandler.class);
	
	/** The exception class. */
	private final Class exceptionClass;
	
	/** The registered classes. */
	private final Set> registeredClasses = new LinkedHashSet<>();
	
	/** The exception block. */
	private final ExceptionBlock exceptionBlock;
	
	/** The terminal flag */
	private final boolean isTerminal;
	
	/**
	 * Instantiates a new exception handler.
	 *
	 * @param exceptionClass the exception class
	 * @param exceptionBlock the exception block
	 */
	public ExceptionHandler(Class exceptionClass, ExceptionBlock exceptionBlock) {
		this.exceptionClass = exceptionClass;
		this.exceptionBlock = exceptionBlock;
		this.registeredClasses.add(exceptionClass);
		this.isTerminal = true;
	}

	/**
	 * Instantiates a new exception handler.
	 *
	 * @param exceptionClass the exception class
	 * @param exceptionBlock the exception block
	 * @param terminal the terminal flag
	 */
	private ExceptionHandler(Class exceptionClass, ExceptionBlock exceptionBlock, boolean isTerminal) {
		this.exceptionClass = exceptionClass;
		this.exceptionBlock = exceptionBlock;
		this.registeredClasses.add(exceptionClass);
		this.isTerminal = false;
	}

	/* (non-Javadoc)
	 * @see com.aegisql.util.function.ExceptionBlock#accept(java.lang.Throwable)
	 */
	@Override
	public void accept(T error) throws Throwable {
		exceptionBlock.accept(error);
	}
	
	/**
	 * Gets the exception class.
	 *
	 * @return the exception class
	 */
	public Class getExceptionClass() {
		return exceptionClass;
	}

	/**
	 * Gets the registered exception classes.
	 *
	 * @return the registered exception classes
	 */
	public Set> getRegisteredExceptionClasses() {
		return Collections.unmodifiableSet(registeredClasses);
	}

	/**
	 * Or catch.
	 *
	 * @param  the generic type
	 * @param t2Class the t2 class
	 * @param eb the eb
	 * @return the exception handler
	 */
	public  ExceptionHandler orCatch(final Class t2Class,ExceptionBlock eb) {
		Objects.requireNonNull(eb);
		
		if(this.registeredClasses.contains(t2Class)) {
			throw new RuntimeException("Class already registered: "+t2Class.getName());
		}
		
		Class tClass = this.getExceptionClass();
		boolean tFo = tClass.isAssignableFrom(t2Class);
		boolean oFt = t2Class.isAssignableFrom(tClass);
		
		ExceptionHandler eh = new ExceptionHandler(t2Class,(T2 t)->{
			Class errClass = t.getClass();
			
			boolean tFe = tClass.isAssignableFrom(errClass);
			boolean eFt = errClass.isAssignableFrom(tClass);

			boolean oFe = t2Class.isAssignableFrom(errClass);
			boolean eFo = errClass.isAssignableFrom(t2Class);
			
			log.trace("this:<"+tClass.getSimpleName()+"> other:<"+t2Class.getSimpleName()+"> actual:<"+errClass.getSimpleName()+">");
			log.trace("t<->o:{}<->{}; t<->e:{}<->{}; o<->e:{}<->{};",tFo,oFt,tFe,eFt,oFe,eFo);
			
			try {
				
				if(tFe && eFt) {
					log.trace("It's this:<{}>",errClass.getSimpleName());
					this.accept((T)t);
					return;
				}

				if(oFe && eFo) {
					log.trace("It's other:<{}>",errClass.getSimpleName());
					eb.accept(t);
					return;
				}

				try {
					if(!tFe && !eFt && !isTerminal) {
						log.trace("Try <{}> anyway with:<{}>",tClass.getSimpleName(),errClass.getSimpleName());
						T ex = (T)t;
						this.accept(ex);
						return;
					}
				} catch(Throwable x) {
					if(x == t) {
						if(!oFe && !eFo) {
							log.trace("Try <{}> last time with:<{}>",t2Class.getSimpleName(),errClass.getSimpleName());
							eb.accept(t);
							return;
						}
					} else {
						throw x;
					}
				}

				T tt = tClass.cast(t);
				log.trace("sending to <{}> :<{}>",tClass.getSimpleName(),errClass.getSimpleName());
				this.accept(tt);
			} catch(ClassCastException t2) {
				try {
					t2Class.cast(t);
				}  catch(ClassCastException t4) {
					log.trace("give up with <{}>",errClass.getSimpleName());
					throw t;
				}
				log.trace("sending to <{}> :<{}>",t2Class.getSimpleName(),errClass.getSimpleName());
				eb.accept(t);
			} catch (Throwable t3) {
				throw t3;
			}
		},false);
		eh.registeredClasses.addAll(this.registeredClasses);
		
		return eh;
	}

	/**
	 * Wrap throwable.
	 *
	 * @param  the generic type
	 * @return the function
	 */
	public static  Function,Function> wrapThrowable() {
		return wr->thr->{
			try {
				Constructor con = wr.getConstructor(Throwable.class);
				return con.newInstance(thr);
			} catch (Exception e) {
				throw new RuntimeException("(Throwable) constructor is unavailable for "+wr.getName(),e);
			}
		};
	}

	
	/**
	 * Wrap commented throwable.
	 *
	 * @param  the generic type
	 * @return the function
	 */
	public static  Function,Function>> wrapCommentedThrowable() {
		return wr->str->thr->{
			try {
				Constructor con = wr.getConstructor(String.class,Throwable.class);
				return con.newInstance(str,thr);
			} catch (Exception e) {
				throw new RuntimeException("(String,Throwable) constructor is unavailable for "+wr.getName(),e);
			}
		};
	}
	
	/**
	 * To string.
	 *
	 * @param t the t
	 * @return the string
	 */
	public static String toString(Throwable t) {
		StringWriter sw = new StringWriter();
		t.printStackTrace(new PrintWriter(sw));
		String exceptionAsString = sw.toString();
		return exceptionAsString;
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy