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

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

// EDS Classes
import gov.va.med.fw.service.ServiceConfigurationException;
import gov.va.med.fw.util.GenericExceptionHandler;

/**
 * Provides an exception handler that can traverse to the specific exception in
 * an exception chain to handle.  A derived class must provide an exception name
 * in an exception chain to handle through a property "exceptionName".
 * 
 * @author Vu Le
 * @version 1.0
 */
public abstract class AbstractChainExceptionHandler extends GenericExceptionHandler {

    // An exception name in a chain to handle
    private String exceptionName = null; 
    
    /**
     * A default exception handler 
     */
    protected AbstractChainExceptionHandler() {
        super();
    }

    /**
     * Checks if a exceptionName in an exception chain is specified.
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    public void afterPropertiesSet() throws Exception {
        if( StringUtils.isBlank( exceptionName ) ) {
            throw new ServiceConfigurationException( "Missing required exception name to handle" );
        }
    }
    
    /**
     * Logs an exception to a logger then returns an exception to a caller for
     * processing
     * 
     * @param exception An exception to handle
     * @param string An exception message
     * @param originator An exception's originator
     */
    /**
     * @see gov.va.med.fw.util.ExceptionHandler#handleException(java.lang.Exception, java.lang.String, java.lang.Object)
     */
    public Exception handleException( Exception exception, String message, Object originator) {

        Throwable[] causes = ExceptionUtils.getThrowables( exception );
        for( int i=0; i<causes.length; i++ ) {
            Throwable cause = causes[i];
            if( cause.getClass().getName().equals( getExceptionName() ) ) {
                exception = this.processNestedException( cause, message, originator );
            }
        }
        return exception;
    }
    
    /**
     * @return Returns the exceptionName.
     */
    public String getExceptionName() {
        return exceptionName;
    }
    
    /**
     * @param exceptionName The exceptionName to set.
     */
    public void setExceptionName(String exceptionName) {
        this.exceptionName = exceptionName;
    }
    
    /** Processes a nested exception 
     * 
     * @param exception An exception containing a nested exception in its chain
     * @param message An exception message
     * @param originator An originator of an exception
     * @return Exception an exception to return to a caller for upstream handling.
     */
    protected abstract Exception processNestedException( Throwable exception, String message, Object originator );
}