1. /*
  2. * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ControllerThreadSocketFactory.java,v 1.2 2004/04/18 23:51:38 jsdever Exp $
  3. * $Revision: 1.2 $
  4. * $Date: 2004/04/18 23:51:38 $
  5. *
  6. * ====================================================================
  7. *
  8. * Copyright 2002-2004 The Apache Software Foundation
  9. *
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. * ====================================================================
  22. *
  23. * This software consists of voluntary contributions made by many
  24. * individuals on behalf of the Apache Software Foundation. For more
  25. * information on the Apache Software Foundation, please see
  26. * <http://www.apache.org/>.
  27. *
  28. */
  29. package org.apache.commons.httpclient.protocol;
  30. import java.io.IOException;
  31. import java.net.InetAddress;
  32. import java.net.Socket;
  33. import java.net.UnknownHostException;
  34. import org.apache.commons.httpclient.ConnectTimeoutException;
  35. import org.apache.commons.httpclient.util.TimeoutController;
  36. /**
  37. * This helper class is intedned to help work around the limitation of older Java versions
  38. * (older than 1.4) that prevents from specifying a connection timeout when creating a
  39. * socket. This factory executes a controller thread overssing the process of socket
  40. * initialisation. If the socket constructor cannot be created within the specified time
  41. * limit, the controller terminates and throws an {@link ConnectTimeoutException}
  42. *
  43. * @author Ortwin Glueck
  44. * @author Oleg Kalnichevski
  45. *
  46. * @since 3.0
  47. */
  48. public final class ControllerThreadSocketFactory {
  49. private ControllerThreadSocketFactory() {
  50. super();
  51. }
  52. /**
  53. * This method spawns a controller thread overseeing the process of socket
  54. * initialisation. If the socket constructor cannot be created within the specified time
  55. * limit, the controller terminates and throws an {@link ConnectTimeoutException}
  56. *
  57. * @param host the host name/IP
  58. * @param port the port on the host
  59. * @param localAddress the local host name/IP to bind the socket to
  60. * @param localPort the port on the local machine
  61. * @param timeout the timeout value to be used in milliseconds. If the socket cannot be
  62. * completed within the given time limit, it will be abandoned
  63. *
  64. * @return a connected Socket
  65. *
  66. * @throws IOException if an I/O error occurs while creating the socket
  67. * @throws UnknownHostException if the IP address of the host cannot be
  68. * determined
  69. * @throws ConnectTimeoutException if socket cannot be connected within the
  70. * given time limit
  71. *
  72. */
  73. public static Socket createSocket(
  74. final ProtocolSocketFactory socketfactory,
  75. final String host,
  76. final int port,
  77. final InetAddress localAddress,
  78. final int localPort,
  79. int timeout)
  80. throws IOException, UnknownHostException, ConnectTimeoutException
  81. {
  82. SocketTask task = new SocketTask() {
  83. public void doit() throws IOException {
  84. setSocket(socketfactory.createSocket(host, port, localAddress, localPort));
  85. }
  86. };
  87. try {
  88. TimeoutController.execute(task, timeout);
  89. } catch (TimeoutController.TimeoutException e) {
  90. throw new ConnectTimeoutException(
  91. "The host did not accept the connection within timeout of "
  92. + timeout + " ms");
  93. }
  94. Socket socket = task.getSocket();
  95. if (task.exception != null) {
  96. throw task.exception;
  97. }
  98. return socket;
  99. }
  100. public static Socket createSocket(final SocketTask task, int timeout)
  101. throws IOException, UnknownHostException, ConnectTimeoutException
  102. {
  103. try {
  104. TimeoutController.execute(task, timeout);
  105. } catch (TimeoutController.TimeoutException e) {
  106. throw new ConnectTimeoutException(
  107. "The host did not accept the connection within timeout of "
  108. + timeout + " ms");
  109. }
  110. Socket socket = task.getSocket();
  111. if (task.exception != null) {
  112. throw task.exception;
  113. }
  114. return socket;
  115. }
  116. /**
  117. * Helper class for wrapping socket based tasks.
  118. */
  119. public static abstract class SocketTask implements Runnable {
  120. /** The socket */
  121. private Socket socket;
  122. /** The exception */
  123. private IOException exception;
  124. /**
  125. * Set the socket.
  126. * @param newSocket The new socket.
  127. */
  128. protected void setSocket(final Socket newSocket) {
  129. socket = newSocket;
  130. }
  131. /**
  132. * Return the socket.
  133. * @return Socket The socket.
  134. */
  135. protected Socket getSocket() {
  136. return socket;
  137. }
  138. /**
  139. * Perform the logic.
  140. * @throws IOException If an IO problem occurs
  141. */
  142. public abstract void doit() throws IOException;
  143. /** Execute the logic in this object and keep track of any exceptions. */
  144. public void run() {
  145. try {
  146. doit();
  147. } catch (IOException e) {
  148. exception = e;
  149. }
  150. }
  151. }
  152. }