
package uk.co.wingpath.io;

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

/**
* This class provides a simple general-purpose UDP socket server.
*/

public class UdpServer
    implements Runnable
{
    private final int port;
    private final Service service;
    private final DatagramSocket socket;
    private final Reporter reporter;
    private final Connection connection;

    /**
    * Constructs a {@code UdpServer}.
    * <p>A UDP socket is opened using the specified {@code host} and
    * {@code port}.
    * @param host name of interface on which to listen for requests.
    * May be {@code null} if any interface may be used.
    * @param port port on which to listen for requests.
    * @param service the service to be provided on the connection.
    * @param reporter to report exceptions thrown by the service.
    * @throws IOException if the socket could not be opened.
    */
    public UdpServer (String host, int port, Service service,
            Reporter reporter)
        throws IOException
    {
        this.reporter = reporter;
        if (host == null)
            host = "";
        try
        {
            if (!host.equals (""))
                socket = new DatagramSocket (port,
                    InetAddress.getByName (host));
            else
                socket = new DatagramSocket (port);
            this.port = port;
            this.service = service;
            connection = new UdpConnection (socket);
        }
        catch (BindException e)
        {
            if (host.equals (""))
            {
                throw new HIOException ("I113", "Can't listen on port " + port);
            }
            else
            {
                throw new HIOException ("I114",
                    "Can't listen on interface '" + host + "' port " + port);
            }
        }
        catch (UnknownHostException e)
        {
            throw new HIOException ("I115", "Unknown host: " + host);
        }
    }

    /**
    * Calls the {@link Service#serve serve} method of the supplied service.
    * <p>This method should normally be called in its own thread.
    * <p>Any {@code IOException}s thrown by the {@code serve} method are
    * passed to the exception handler.
    * <p>This method closes the UDP socket before it returns.
    */
    public void run ()
    {
        Event.checkIsNotEventDispatchThread ();
        try
        {
            service.serve (connection);
        }
        catch (InterruptedException 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 ();
        }
    }
}


