001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jnp.interfaces;
023:
024: import java.io.IOException;
025: import java.net.ConnectException;
026: import java.net.InetAddress;
027: import java.net.Socket;
028: import java.net.UnknownHostException;
029: import java.util.Hashtable;
030: import javax.net.SocketFactory;
031:
032: /** A concrete implementation of the SocketFactory that supports a configurable
033: timeout for the initial socket connection as well as the SO_TIMEOUT used to
034: determine how long a read will block waiting for data.
035:
036: @author Scott.Stark@jboss.org
037: @version $Revision: 57199 $
038: */
039: public class TimedSocketFactory extends SocketFactory {
040: public static final String JNP_TIMEOUT = "jnp.timeout";
041: public static final String JNP_SO_TIMEOUT = "jnp.sotimeout";
042:
043: /** The connection timeout in milliseconds */
044: protected int timeout = 0;
045: /** The SO_TIMEOUT in milliseconds */
046: protected int soTimeout = 0;
047:
048: /** Creates a new instance of TimedSocketFactory */
049: public TimedSocketFactory() {
050: }
051:
052: public TimedSocketFactory(Hashtable env) {
053: String value = (String) env.get(JNP_TIMEOUT);
054: if (value != null)
055: timeout = Integer.parseInt(value);
056: value = (String) env.get(JNP_SO_TIMEOUT);
057: if (value != null)
058: soTimeout = Integer.parseInt(value);
059: }
060:
061: public Socket createSocket(String host, int port)
062: throws IOException, UnknownHostException {
063: InetAddress hostAddr = InetAddress.getByName(host);
064: return this .createSocket(hostAddr, port, null, 0);
065: }
066:
067: public Socket createSocket(InetAddress hostAddr, int port)
068: throws IOException {
069: return this .createSocket(hostAddr, port, null, 0);
070: }
071:
072: public Socket createSocket(String host, int port,
073: InetAddress localAddr, int localPort) throws IOException,
074: UnknownHostException {
075: InetAddress hostAddr = InetAddress.getByName(host);
076: return this .createSocket(hostAddr, port, localAddr, localPort);
077: }
078:
079: public Socket createSocket(InetAddress hostAddr, int port,
080: InetAddress localAddr, int localPort) throws IOException {
081: Socket socket = null;
082: if (timeout <= 0)
083: socket = new Socket(hostAddr, port, localAddr, localPort);
084: else
085: socket = createSocket(hostAddr, port, localAddr, localPort,
086: timeout);
087:
088: socket.setSoTimeout(soTimeout);
089: return socket;
090: }
091:
092: protected Socket createSocket(InetAddress hostAddr, int port,
093: InetAddress localAddr, int localPort, int connectTimeout)
094: throws IOException {
095: ConnectThread t = new ConnectThread();
096: Socket socket = t.createSocket(hostAddr, port, localAddr,
097: localPort, connectTimeout);
098: return socket;
099: }
100:
101: /** A subclass of Thread used to time the blocking connect operation
102: and notify the thread attempting the socket connect of a timeout.
103: */
104: class ConnectThread extends Thread {
105: IOException ex;
106: InetAddress hostAddr;
107: InetAddress localAddr;
108: int port;
109: int localPort;
110: int connectTimeout;
111: Socket socket;
112:
113: ConnectThread() {
114: super ("JNP ConnectThread");
115: super .setDaemon(true);
116: }
117:
118: /** Perform the connection in a background thread and wait upto
119: connectTimeout milliseconds for it to complete before throwing
120: a ConnectionException
121: */
122: Socket createSocket(InetAddress hostAddr, int port,
123: InetAddress localAddr, int localPort, int connectTimeout)
124: throws IOException {
125: this .hostAddr = hostAddr;
126: this .port = port;
127: this .localAddr = localAddr;
128: this .localPort = localPort;
129: this .connectTimeout = connectTimeout;
130:
131: try {
132: synchronized (this ) {
133: // Perform the socket connection in a background thread
134: this .start();
135: // Wait for upto connectTimeout milliseconds for the connection
136: this .wait(connectTimeout);
137: }
138: } catch (InterruptedException e) {
139: throw new ConnectException("Connect attempt timed out");
140: }
141:
142: // See if the connect thread exited due to an exception
143: if (ex != null)
144: throw ex;
145: // If socket is null we timed out while waiting
146: if (socket == null)
147: throw new ConnectException("Connect attempt timed out");
148:
149: return socket;
150: }
151:
152: public void run() {
153: try {
154: socket = new Socket(hostAddr, port, localAddr,
155: localPort);
156: synchronized (this ) {
157: this .notify();
158: }
159: } catch (IOException e) {
160: this.ex = e;
161: }
162: }
163: }
164: }
|