View Javadoc

1   /*
2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/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: 155418 $
4    * $Date: 2005-02-26 08:01:52 -0500 (Sat, 26 Feb 2005) $
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  
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 }