
package uk.co.wingpath.io;

import java.io.*;
import java.net.*;
import uk.co.wingpath.util.*;
import uk.co.wingpath.event.*;

/**
* This class is used to wrap a Service in a Runnable so that it can be run
* by an Executor.
*/
public class ServiceTask
    implements Runnable
{
    private final Connection connection;
    private final Service service;
    private final Reporter reporter;
    private final Thread shutdownHook;

    /**
    * Constructs a {@code ServiceTask}.
    * @param connection the connection on which the service is to be provided.
    * @param service the service.
    * @param reporter to report exceptions thrown by the
    * {@code serve} method of the service.
    */
    public ServiceTask (final Connection connection, Service service,
        Reporter reporter)
    {
        this.connection = connection;
        this.service = service;
        this.reporter = reporter;

        shutdownHook = new Thread (
            new Runnable ()
            {
                public void run ()
                {
                    connection.close ();
                }
            },
            "ServiceTask-Shutdown");
        try
        {
            Runtime.getRuntime ().addShutdownHook (shutdownHook);
        }
        catch (IllegalStateException e)
        {
            // Happens if already shutting down.
        }
        catch (SecurityException e)
        {
            // May happen if called from applet.
        }
    }

    /**
    * Calls the {@code serve} method of the service.
    * <p>Any {@code IOException}s (other than {@code EOFException}) thrown by
    * the {@code serve} method are passed to the exception handler.
    * <p>This method closes the service connection before it returns.
    */
    public void run ()
    {
        Event.checkIsNotEventDispatchThread ();
        try
        {
            service.serve (connection);
        }
        catch (InterruptedException e)
        {
        }
        catch (EOFException e)
        {
        }
        catch (HIOException e)
        {
            if (reporter != null)
                reporter.error (e.getHelpId (), Exceptions.getMessage (e));
        }
        catch (IOException e)
        {
            if (reporter != null)
                reporter.error (null, Exceptions.getMessage (e));
        }
        finally
        {
            connection.close ();
            try
            {
                Runtime.getRuntime ().removeShutdownHook (shutdownHook);
            }
            catch (IllegalStateException e)
            {
                // Happens if already shutting down.
            }
            catch (SecurityException e)
            {
                // May happen if called from applet.
            }
        }
    }
}


