1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.apache.commons.httpclient.protocol;
31
32 import java.io.IOException;
33 import java.net.InetAddress;
34 import java.net.Socket;
35 import java.net.UnknownHostException;
36
37 import org.apache.commons.httpclient.ConnectTimeoutException;
38 import org.apache.commons.httpclient.util.TimeoutController;
39
40 /***
41 * This helper class is intedned to help work around the limitation of older Java versions
42 * (older than 1.4) that prevents from specifying a connection timeout when creating a
43 * socket. This factory executes a controller thread overssing the process of socket
44 * initialisation. If the socket constructor cannot be created within the specified time
45 * limit, the controller terminates and throws an {@link ConnectTimeoutException}
46 *
47 * @author Ortwin Glueck
48 * @author Oleg Kalnichevski
49 *
50 * @since 3.0
51 */
52 public final class ControllerThreadSocketFactory {
53
54 private ControllerThreadSocketFactory() {
55 super();
56 }
57
58 /***
59 * This method spawns a controller thread overseeing the process of socket
60 * initialisation. If the socket constructor cannot be created within the specified time
61 * limit, the controller terminates and throws an {@link ConnectTimeoutException}
62 *
63 * @param host the host name/IP
64 * @param port the port on the host
65 * @param localAddress the local host name/IP to bind the socket to
66 * @param localPort the port on the local machine
67 * @param timeout the timeout value to be used in milliseconds. If the socket cannot be
68 * completed within the given time limit, it will be abandoned
69 *
70 * @return a connected Socket
71 *
72 * @throws IOException if an I/O error occurs while creating the socket
73 * @throws UnknownHostException if the IP address of the host cannot be
74 * determined
75 * @throws ConnectTimeoutException if socket cannot be connected within the
76 * given time limit
77 *
78 */
79 public static Socket createSocket(
80 final ProtocolSocketFactory socketfactory,
81 final String host,
82 final int port,
83 final InetAddress localAddress,
84 final int localPort,
85 int timeout)
86 throws IOException, UnknownHostException, ConnectTimeoutException
87 {
88 SocketTask task = new SocketTask() {
89 public void doit() throws IOException {
90 setSocket(socketfactory.createSocket(host, port, localAddress, localPort));
91 }
92 };
93 try {
94 TimeoutController.execute(task, timeout);
95 } catch (TimeoutController.TimeoutException e) {
96 throw new ConnectTimeoutException(
97 "The host did not accept the connection within timeout of "
98 + timeout + " ms");
99 }
100 Socket socket = task.getSocket();
101 if (task.exception != null) {
102 throw task.exception;
103 }
104 return socket;
105 }
106
107 public static Socket createSocket(final SocketTask task, int timeout)
108 throws IOException, UnknownHostException, ConnectTimeoutException
109 {
110 try {
111 TimeoutController.execute(task, timeout);
112 } catch (TimeoutController.TimeoutException e) {
113 throw new ConnectTimeoutException(
114 "The host did not accept the connection within timeout of "
115 + timeout + " ms");
116 }
117 Socket socket = task.getSocket();
118 if (task.exception != null) {
119 throw task.exception;
120 }
121 return socket;
122 }
123
124 /***
125 * Helper class for wrapping socket based tasks.
126 */
127 public static abstract class SocketTask implements Runnable {
128 /*** The socket */
129 private Socket socket;
130 /*** The exception */
131 private IOException exception;
132
133 /***
134 * Set the socket.
135 * @param newSocket The new socket.
136 */
137 protected void setSocket(final Socket newSocket) {
138 socket = newSocket;
139 }
140
141 /***
142 * Return the socket.
143 * @return Socket The socket.
144 */
145 protected Socket getSocket() {
146 return socket;
147 }
148 /***
149 * Perform the logic.
150 * @throws IOException If an IO problem occurs
151 */
152 public abstract void doit() throws IOException;
153
154 /*** Execute the logic in this object and keep track of any exceptions. */
155 public void run() {
156 try {
157 doit();
158 } catch (IOException e) {
159 exception = e;
160 }
161 }
162 }
163 }