/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.fw.util;

//Java Classes
import java.lang.reflect.InvocationTargetException;

//Library classes
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.ClassUtils;

//Framework Classes
import gov.va.med.fw.service.AbstractComponent;
import gov.va.med.fw.util.ExceptionHandler;
import gov.va.med.fw.util.Reflector;

/**
 * This base exception handler class uses reflection to look for a 
 * specific handleXXX method in a derived class to handle the specific 
 * exception in a chain.
 * 
 * @author Vu Le
 * @version 1.0
 */
public abstract class AbstractExceptionHandler extends AbstractComponent implements ExceptionHandler {

	private boolean continueToHandle = false;
	
	protected final static String DEFAULT_HANDLER_METHOD_PREFIX = "handle";
	
	protected AbstractExceptionHandler() {
		super();
	}

	/**
	 * Process an exceptions
	 * 
	 * @param exception An exception to handle
	 * @param exceptionMessage An exception message
	 * @param originator An exception's originator
	 */
	public Throwable handleException( Throwable exception,
												 String exceptionMessage, 
												 Object originator ) {

		// Obtain all exceptions thrown in a chain to look for 
		// specific exception handling method in a derived class 

		// Get a list of all exceptions in a chain. If an exception
		// is null, an array of 0 element is returned so we don't 
		// need to check for 0 array here
		Throwable[] causes = ExceptionUtils.getThrowables( exception );
		for( int i=0; i<causes.length; i++ ) {
			
			// For each throwable in an array, look for a 
			// handleXXX method in a derived class to call if one exists.  
			// For instance, if a BuilderException is found in an array
			// we look for handleBuilderException method in a derived class
			// to call.
			
			// Get an exception class name without the package and append it
			// to the end of a default prefix.  For instance, handleBuilderException
			
			String exceptionName = ClassUtils.getShortClassName( causes[i].getClass() );
			StringBuffer methodName = new StringBuffer( DEFAULT_HANDLER_METHOD_PREFIX );
			methodName.append( exceptionName );
			
			try {
				Reflector.invoke( this, 
										methodName.toString(), 
										new Object[] { exception, exceptionMessage, originator } );
				
				// Now that an exception is handled successfully, only continue if the 
				// derived class sets the flag to true
				if( !this.isContinueToHandle() ) {
					break;
				}
			}
			catch( InvocationTargetException e ) {
				// This exception is thrown when the underlying method throws an exception
				// In this case, ew break out of a loop if a 
				if( !this.isContinueToHandle() ) {
					break;
				}
			}
			catch( Exception e ) {
				// Catch all exceptions that were thrown because an exception handler method
				// for the specific exception has not been found so we continue on looking 
				// for the handler method
			}
		}
		return exception;
	}
	
	/**
	 * @return Returns the continueToHandle.
	 */
	public boolean isContinueToHandle() {
		return continueToHandle;
	}
	/**
	 * @param continueToHandle The continueToHandle to set.
	 */
	public void setContinueToHandle(boolean continueToHandle) {
		this.continueToHandle = continueToHandle;
	}
}