/**
 * Created on 4:50:55 PM Jan 3, 2005
 * Project: Framework
 * 
 * @author DNS   LEV
 */
package gov.va.med.fw.rule;

// Java classes
import java.lang.reflect.Member;

// ILOG classes
import ilog.rules.engine.IlrExceptionHandler;
import ilog.rules.engine.IlrUserRuntimeException;

// Third party classes
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * A generic rule exception handler that handles user exception triggered in an evaluation or 
 * action part of a rule.  This exception handler is set into a IlrContext of a rule set only 
 * if the exception handler is set in a Rule wrapper class through its rule interface. 
 */
public class RuleExceptionHandler implements IlrExceptionHandler {

   /**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = 5121662021596048477L;
	/**
    * An instance of a log component used for logging information
    */ 
   protected Log logger = LogFactory.getLog( getClass() );
   
   /**
    * An instance of ruleFlowName
    */
   private String ruleFlowName = null;
   
   /**
    * A default constructor
    */
   public RuleExceptionHandler() {
      super();
   }
   
   /** Handles exception triggered in a condition or an evaluation part of a rule.
    * A boolean value is returned to indicate whether a rule is processed successfully
    * 
    * @see ilog.rules.engine.IlrExceptionHandler#handleException(ilog.rules.engine.IlrUserRuntimeException)
    */
   public boolean handleException( IlrUserRuntimeException e ) {
      
      boolean handled = false;

      if( e.isInActions() ) {
         processActionException( e );
      }
      else if( e.isInConditions() ) {
         handled = processConditionException( e );
      }
      else {
         processInternalException( e );
      }
      return handled;
   }
   

	/**
	 * @return Returns the ruleFlowName.
	 */
	public String getRuleFlowName() {
		return ruleFlowName;
	}

	/**
	 * @param ruleFlowName The ruleFlowName to set.
	 */
	public void setRuleFlowName(String ruleFlowName) {
		this.ruleFlowName = ruleFlowName;
	}

	/** Log an exception thrown in a condition part of a rule
    * @param e An exception to be processed
    * @return False to indicate a rule is not processed. True otherwise
    */
   protected boolean processConditionException( IlrUserRuntimeException e ) {
      logException( e );
      return false;
   }

   /** Log an exception thrown in an action part of a rule then re-throw it
    * @param e An exception to be processed
    */
   protected void processActionException( IlrUserRuntimeException e ) {
      logException( e );
      throw e;
   }

   /** Log an exception thrown in an action part of a rule then re-throw it
    * @param e An exception to be processed
    */
   protected void processInternalException( IlrUserRuntimeException e ) {
      logException( e );
      throw e;
   }

   /** Log an exception.  If an error level is set, an exception and its 
    * member (method or field) from which an exception is triggered is logged
    * 
    * @param e An exception to be logged
    */
   protected void logException( IlrUserRuntimeException e ) {
      if( logger.isDebugEnabled() ) {
         Member member = e.getTargetMember();
         String name = (member != null) ? member.getName() : null;
         Throwable target = e.getTargetException();
         String targetName = (target != null) ? target.getClass().getName() : null;
         
         logger.debug( "An exception occured in a rule flow: " + this.getRuleFlowName() );
         logger.debug( "An exception occured in a rule: " + name );
         logger.debug( "A root cause exception: " + targetName );
         logger.debug( "Exception details: " + e.getMessage(), e );
      }
      throw e;
   }
}