// SocketOpener.java
// Copyright (C) 1997 by Wayne E. Conrad
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA


package com.yagni.socketopener;


import java.io.*;
import java.net.*;


public class SocketOpener
  {


  // The SocketFactory class creates the socket.

  interface SocketFactory
    {
    Socket makeSocket() throws IOException;
    };
  SocketFactory socketFactory;


  // The socket, or null if it couldn't be created.

  Socket socket;


  // The exception that occured when creating the socket, or null if no
  // exception occured.

  IOException ioexception;


  // Constructor.  This SocketOpener will use Socket (String, int) to create
  // the socket.

  public SocketOpener (final String host, final int port)
    {
    socketFactory = new SocketFactory()
      {
      public Socket makeSocket() throws IOException
        {return new Socket (host, port);}
      };
    }


  // Constructor.  This SocketOpener will use Socket (InetAddress, int, int)
  // to create the socket.

  public SocketOpener (final InetAddress address, final int port)
    {
    socketFactory = new SocketFactory()
      {
      public Socket makeSocket() throws IOException
        {return new Socket (address, port);}
      };
    }


  // Constructor.  This SocketOpener will use Socket (String, int,
  // InetAddress, int) to create the socket.

  public SocketOpener
  (
  final String host, final int port,
  final InetAddress localAddr, final int localPort
  )
    {
    socketFactory = new SocketFactory()
      {
      public Socket makeSocket() throws IOException
        {return new Socket (host, port, localAddr, localPort);}
      };
    }


  // Constructor.  This SocketOpener will use Socket (String, int,
  // InetAddress, int) to create the socket.

  public SocketOpener
  (
  final InetAddress address, final int port,
  final InetAddress localAddr, final int localPort
  )
    {
    socketFactory = new SocketFactory()
      {
      public Socket makeSocket() throws IOException
        {return new Socket (address, port, localAddr, localPort);}
      };
    }


  // Open the socket with a timeout in milliseconds.  If timeout == 0, then
  // use the socket's natural timeout.  Note that if timeout is greater than
  // the socket's natural timeout, the natural timeout will happen anyhow.

  public synchronized Socket makeSocket (long timeout) throws IOException
    {
    socket = null;
    ioexception = null;
    Thread socketThread = new Thread()
      {
      public void run()
        {
        try {socket = socketFactory.makeSocket();}
        catch (IOException e) {ioexception = e;}
        }
      };
    socketThread.setName ("MakeSocketThread");
    socketThread.setDaemon (true);
    socketThread.start();
    try
      {socketThread.join (timeout);}
    catch (InterruptedException e)
      {}
    socketThread.stop();
    if (ioexception != null)
      throw ioexception;
    if (socket == null)
      throw new TimeoutException();
    return socket;
    }


  };
