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