/*
 * ObjectSocketHandler.java
 *
 * Created on 13 March 2003, 10:18
 */

package org.bodington.logging;

import java.net.*;
import java.io.*;
import java.util.logging.*;

/**
 *
 * @author  jrm
 */
public class ObjectSocketHandler extends java.util.logging.Handler
{
    
    private Socket sock;
    private String host;
    private int port;
    private String portProperty;
    
    private int connect_attempt_count=0;
    
    ObjectOutputStream oos=null;
    
    // Private method to configure a SocketHandler from LogManager
    // properties and/or default values as specified in the class
    // javadoc.
    private void configure()
    {
        setLevel( Level.ALL );
        setFilter( null );
        port = 0;
        host = "localhost";
    }
    
    
    /**
     * Create a <tt>SocketHandler</tt>, using only <tt>LogManager</tt> properties
     * (or their defaults).
     * @throws IllegalArgumentException if the host or port are invalid or
     *		are not specified as LogManager properties.
     * @throws IOException if we are unable to connect to the target
     *	       host and port.
     */
    public ObjectSocketHandler() throws IOException
    {
        throw new IOException( "Constructor requires host and port." );
    }
    
    /**
     * Construct a <tt>SocketHandler</tt> using a specified host and port.
     *
     * The <tt>SocketHandler</tt> is configured based on <tt>LogManager</tt>
     * properties (or their default values) except that the given target host
     * and port arguments are used.
     *
     * @param host target host.
     * @param port target port.
     *
     * @throws IllegalArgumentException if the host or port are invalid.
     * @throws IOException if we are unable to connect to the target
     *	       host and port.
     */
    public ObjectSocketHandler(String host, int port) throws IOException
    {
        if ( host == null || port == 0 )
            throw new IOException( "Constructor requires host and port." );
        
        configure();
        this.port = port;
        this.host = host;
        connect();
    }
    
    private void connect()
    {
        connect_attempt_count++;
        if ( connect_attempt_count==50 )
            connect_attempt_count = 1;
        if ( connect_attempt_count>1 )
            return;
        
        connect_attempt_count=0;
        
        try
        {
            // Try to open a new socket.
            sock = new Socket(host, port);
            OutputStream out = sock.getOutputStream();
            BufferedOutputStream bout = new BufferedOutputStream(out);
            oos = new ObjectOutputStream( bout );
        }
        catch ( Exception e )
        {
            oos = null;
        }
    }
    
    /**
     * Close this output stream.
     *
     * @exception  SecurityException  if a security manager exists and if
     *             the caller does not have <tt>LoggingPermission("control")</tt>.
     */
    public synchronized void close() throws SecurityException
    {
        if (sock != null)
        {
            try
            {
                if ( oos != null )
                {
                    oos.close();
                    oos = null;
                }
                sock.close();
            }
            catch (IOException ix)
            {
                // drop through.
            }
        }
        sock = null;
    }
    
    /**
     * Format and publish a <tt>LogRecord</tt>.
     *
     * @param  record  description of the log event
     */
    public synchronized void publish(LogRecord record)
    {
        if (!isLoggable(record))
        {
            return;
        }
        
        try
        {
            if ( oos == null )
                connect();
            
            oos.writeObject( record );
            //logrecords don't reference each other - there's no need for
            //a huge collection of records.  reset() makes oos forget
            //previous objects in the stream and resets tables etc.
            oos.reset();
        }
        catch ( Exception e )
        {
            oos = null;
        }
        
    }
    
    /**
     * Flush any buffered messages.
     */
    public synchronized void flush()
    {
        if (oos != null)
        {
            try
            {
                oos.flush();
            }
            catch (Exception ex)
            {
                // We don't want to throw an exception here, but we
                // report the exception to any registered ErrorManager.
                reportError(null, ex, ErrorManager.FLUSH_FAILURE);
            }
        }
    }
}
