/*
/*
 * Copyright (C) The Apache Software Foundation. All rights reserved.
 *
 * This software is published under the terms of the Apache Software
 * License version 1.1, a copy of which has been included with this
 * distribution in the LICENSE.txt file. 
 *
 * FailoverErrorHandler.java
 *
 * Created on June 19, 2003, 7:47 PM
 */

import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.Appender;
import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;

/** The FailoverErrorHandler implements the ErrorHandler interface such that when a
 * secondary Appender is specified, if the primary Appender passes a LoggingEvent
 * into the error() method it is logged via the secondary Appender.  Unlike the
 * FallbackErrorHandler, the FailoverErrorHandler does not remove the primary
 * Appender from the Logger and replace it with the secondary one - alternatively,
 * it announces the error to System.err and simply logs the event via the secondary
 * Appender.  Subclasses of FailoverErrorHandler can override announce() to
 * announce primary Appender failure by other means - such as using a named Logger
 * object configured with other Appender(s).
 * @author Scott Heaberlin (scott@heabdogg.com)
 */
public class FailoverErrorHandler implements ErrorHandler {
    
    private Appender primary = null;
    private Appender backup = null;
    
    /** Creates a new instance of FailoverErrorHandler */
    public FailoverErrorHandler() {
    }
    
    /** The FailoverErrorHandler has no options to activate. */    
    public void activateOptions() {
        //no options to activate in this implementation
    }
    
    /** Announces the error by printing <CODE>message</CODE> to <CODE>System.err</CODE>.
     * @param message The message describing the failure encountered by the primary
     * <CODE>Appender</CODE>
     */    
    public void error(String message) {
        this.announce(message, null, Integer.MAX_VALUE);
    }
    
    /** Prints the error message, exception, and application-specific error code to
     * <CODE>System.err</CODE>.
     * @param message The message describing the failure encountered by the primary
     * <CODE>Appender</CODE>
     * @param exception The Exception which presumably caused the primary Appender to fail.
     * @param errorCode An application specific error code value.
     */    
    public void error(String message, Exception exception, int errorCode) {
        this.announce(message, exception, errorCode);
    }
    
    /** Prints the error message, exception, and application-specific error code to
     * <CODE>System.err</CODE>.<br>
     * The <CODE>LoggingEvent</CODE> is then passed to the backup Appender so that it
     * is not lost due to primary <CODE>Appender</CODE> failure.
     * @param message The message describing the failure encountered by the primary
     * <CODE>Appender</CODE>
     * @param exception The Exception which presumably caused the primary Appender to fail.
     * @param errorCode An application specific error code value.
     * @param loggingEvent The LoggingEvent which was unable to be logged via the primary Appender due to
     * some sort of failure and which should be logged via the backup Appender.
     */    
    public void error(String message, Exception exception, int errorCode, LoggingEvent loggingEvent) {
        this.announce(message, exception, errorCode);
        this.sendToBackup(loggingEvent);
    }
    
    /** Sets the primary <CODE>Appender</CODE>
     * @param appender The primary Appender object
     */    
    public void setAppender(Appender appender) {
        LogLog.debug("FEH: Setting primary Appender to [" + appender.getName() + "]");
        this.primary = appender;
    }
    
    /** Sets the backup <CODE>Appender</CODE> object which will be used to log
     * <CODE>LoggingEvent</CODE> objects in the event of primary <CODE>Appender</CODE>
     * failure.
     * @param appender An Appender to use as a backup in case the primary Appender fails.
     */    
    public void setBackupAppender(Appender appender) {
        LogLog.debug("FEH: Setting backup Appender to [" + appender.getName() + "]");
        this.backup = appender;
    }
    
    /** The Logger object is not used in the <CODE>FailoverErrorHandler</CODE>, as all
     * <CODE>LoggingEvent</CODE> objects are simply logged via the backup Appender.
     * @param logger A Logger
     */    
    public void setLogger(Logger logger) {
        //logger not used in the default implementation
    }
    
    /** Prints the error message, exception, and application-specific error code to
     * <CODE>System.err</CODE>.<br>
     * <br>
     * Subclasses could override this method to use alternative means of announcing
     * errors <i>other</i> than <CODE>System.err</CODE>.
     * @param message The error message to announce
     * @param exception The exception to announce
     * @param errorCode The application-specific error code to include in the announcement.  If this
     * value is <CODE>Integet.MAX_VALUE</CODE>, it will not be printed.
     */    
    protected void announce(String message, Exception exception, int errorCode){
        StringBuffer msgBuffer = new StringBuffer("FEH: Error reported by ");
        msgBuffer.append("[");
        msgBuffer.append(primary.getName());
        msgBuffer.append("]: ");
        msgBuffer.append(message);
        
        if (errorCode != Integer.MAX_VALUE) {
            msgBuffer.append(" error code [");
            msgBuffer.append(errorCode);
            msgBuffer.append("]");            
        }        
        
        if (exception != null){
            LogLog.debug(msgBuffer.toString(), exception);
        } else {
            LogLog.debug(msgBuffer.toString());
        }
    }
    
    /** Sends the event to the backup <CODE>Appender</CODE> to be logged
     * @param event The event which was unable to be logged due to primary <CODE>Appender</CODE>
     * failure.
     */    
    protected void sendToBackup(LoggingEvent event){
        if (backup != null){
            LogLog.debug("FEH: Sending LoggingEvent to backup Appender [" + backup.getName() + "]");
            backup.doAppend(event);
        } else {
            LogLog.warn("FEH: Unable to log event to backup - no backup Appender defined");
        }
    }
    
}

