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: 480424 $
    4    * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
    5    *
    6    * ====================================================================
    7    *
    8    *  Licensed to the Apache Software Foundation (ASF) under one or more
    9    *  contributor license agreements.  See the NOTICE file distributed with
    10   *  this work for additional information regarding copyright ownership.
    11   *  The ASF licenses this file to You under the Apache License, Version 2.0
    12   *  (the "License"); you may not use this file except in compliance with
    13   *  the License.  You may obtain a copy of the License at
    14   *
    15   *      http://www.apache.org/licenses/LICENSE-2.0
    16   *
    17   *  Unless required by applicable law or agreed to in writing, software
    18   *  distributed under the License is distributed on an "AS IS" BASIS,
    19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    20   *  See the License for the specific language governing permissions and
    21   *  limitations under the License.
    22   * ====================================================================
    23   *
    24   * This software consists of voluntary contributions made by many
    25   * individuals on behalf of the Apache Software Foundation.  For more
    26   * information on the Apache Software Foundation, please see
    27   * <http://www.apache.org/>.
    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 }