/*
 * 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.APL file.  
 */

package org.apache.log4j.rmi;

import java.rmi.RemoteException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.net.MalformedURLException;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.helpers.LogLog;

/**
 *
 * @author  Alessandro Di Maria
 * @version 
 */
public class RemoteAppender extends AppenderSkeleton{
    
    /**
     * note that will be appended to the NDC before sending the event to the server.<br>
     */
    private String note;
    
    /**
     * reference to the RemoteNode
     */
    private IRemoteNode server=null;
    
    /**
     * Host of the remote server<br>
     * default = localhost
     */
    private String remoteHost="localhost";
    
    /**
     * port. No default is set.
     */
    private String port;
    
    /**
     * name of the RemoteNode which was bound with the rmiregistery<br>
     * default = RemoteNode
     */
    private String remoteNode="RemoteNode";
    
    /**
     * Reconnection delay, if first time fails.
     */
    private int delay=30000;

    public RemoteAppender() {
    }
    
    public RemoteAppender(String remoteHost){
        this.remoteHost = remoteHost;
    }
    
    public RemoteAppender(String remoteHost, String remoteNode){
        this(remoteHost);
        this.remoteNode = remoteNode;
    }
    
    public RemoteAppender(String remoteHost, String remoteNode, String port){
        this(remoteHost,remoteNode);
        this.port = port;
    }
    
    public void setRemoteHost(String remoteHost){
        this.remoteHost = remoteHost;
    }
    
    public String getRemoteHost(){
        return this.remoteHost;
    }
        
    public void setPort(String port){
        this.port = port;
    }
    
    public void setPort(int port){
        this.port = String.valueOf(port);
    }
    
    public void setRemoteNode(String remoteNode){
        this.remoteNode = remoteNode;
    }
    
    
    public void setNote(String note){
        this.note = note;
    }
    
    public void setDelay(int delay){
        this.delay = delay;
    }
    
    public int getDelay(){
        return this.delay;
    }
    
    /**
     * Search the RemoteNode in the rmiregistery.
     */
    private void lookup(){
        try{
            String strURL;
            if(port!=null){
                strURL = "//"+remoteHost+":"+port+"/"+remoteNode;
            } else {
                strURL = "//"+remoteHost+"/"+remoteNode;
            }
            server = (IRemoteNode)Naming.lookup(strURL);
        } catch (NotBoundException nbe){
            LogLog.error("RemoteNode not bound in registery",nbe);
        } catch (RemoteException re){
            LogLog.error("RemoteException looking up RemoteNode",re);
        } catch (MalformedURLException mue){
            LogLog.error("URL for looking up RemoteNode malformed",mue);
        }
    }
    
    public boolean requiresLayout() {
        return false;
    }
    
    public void close(){
        // ???
    }
    
    /**
     * adds the note to the NDC before sending to remote server.
     */
    public void append(LoggingEvent event){
        if (server==null){
            lookup();
        }
        if (server!=null){            
            if(note!=null){
                event.pushNDC(note);
            }
            new Sender(event).start();
        }
    }
    
    class Sender extends Thread {
        
        private LoggingEvent event;
        
        public Sender(LoggingEvent event){
            this.setDaemon(true);
            this.setPriority(Thread.MIN_PRIORITY);
            this.event = event;
        }
        
        public void run(){
            try{
                RemoteAppender.this.server.receiveEvent(event);
            } catch (RemoteException re){
                LogLog.warn("Could not connect to remote log4j server at ["+RemoteAppender.this.getRemoteHost()+"]. We will try again later.");
                try{
                    this.sleep(RemoteAppender.this.getDelay());
                    this.run();
                } catch (InterruptedException ie){
                    LogLog.error(ie.getMessage());
                }
            }
        }
    }
    
}

