/* * JBoss, the OpenSource J2EE WebOS * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jnp.interfaces; import java.io.IOException; import java.net.ConnectException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.Hashtable; import javax.net.SocketFactory; /** A concrete implementation of the SocketFactory that supports a configurable timeout for the initial socket connection as well as the SO_TIMEOUT used to determine how long a read will block waiting for data. @author Scott.Stark@jboss.org @version $Revision: 1.2 $ */ public class TimedSocketFactory extends SocketFactory { public static final String JNP_TIMEOUT = "jnp.timeout"; public static final String JNP_SO_TIMEOUT = "jnp.sotimeout"; /** The connection timeout in milliseconds */ protected int timeout = 0; /** The SO_TIMEOUT in milliseconds */ protected int soTimeout = 0; /** Creates a new instance of TimedSocketFactory */ public TimedSocketFactory() { } public TimedSocketFactory(Hashtable env) { String value = (String) env.get(JNP_TIMEOUT); if( value != null ) timeout = Integer.parseInt(value); value = (String) env.get(JNP_SO_TIMEOUT); if( value != null ) soTimeout = Integer.parseInt(value); } public Socket createSocket(String host, int port) throws IOException, UnknownHostException { InetAddress hostAddr = InetAddress.getByName(host); return this.createSocket(hostAddr, port, null, 0); } public Socket createSocket(InetAddress hostAddr, int port) throws IOException { return this.createSocket(hostAddr, port, null, 0); } public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) throws IOException, UnknownHostException { InetAddress hostAddr = InetAddress.getByName(host); return this.createSocket(hostAddr, port, localAddr, localPort); } public Socket createSocket(InetAddress hostAddr, int port, InetAddress localAddr, int localPort) throws IOException { Socket socket = null; if( timeout <= 0 ) socket = new Socket(hostAddr, port, localAddr, localPort); else socket = createSocket(hostAddr, port, localAddr, localPort, timeout); socket.setSoTimeout(soTimeout); return socket; } protected Socket createSocket(InetAddress hostAddr, int port, InetAddress localAddr, int localPort, int connectTimeout) throws IOException { ConnectThread t = new ConnectThread(); Socket socket = t.createSocket(hostAddr, port, localAddr, localPort, connectTimeout); return socket; } /** A subclass of Thread used to time the blocking connect operation and notify the thread attempting the socket connect of a timeout. */ class ConnectThread extends Thread { IOException ex; InetAddress hostAddr; InetAddress localAddr; int port; int localPort; int connectTimeout; Socket socket; ConnectThread() { super("JNP ConnectThread"); super.setDaemon(true); } /** Perform the connection in a background thread and wait upto connectTimeout milliseconds for it to complete before throwing a ConnectionException */ Socket createSocket(InetAddress hostAddr, int port, InetAddress localAddr, int localPort, int connectTimeout) throws IOException { this.hostAddr = hostAddr; this.port = port; this.localAddr = localAddr; this.localPort = localPort; this.connectTimeout = connectTimeout; try { synchronized( this ) { // Perform the socket connection in a background thread this.start(); // Wait for upto connectTimeout milliseconds for the connection this.wait(connectTimeout); } } catch(InterruptedException e) { throw new ConnectException("Connect attempt timed out"); } // See if the connect thread exited due to an exception if( ex != null ) throw ex; // If socket is null we timed out while waiting if( socket == null ) throw new ConnectException("Connect attempt timed out"); return socket; } public void run() { try { socket = new Socket(hostAddr, port, localAddr, localPort); synchronized( this ) { this.notify(); } } catch(IOException e) { this.ex = e; } } } }