View Javadoc

    1   /*
    2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/protocol/ReflectionSocketFactory.java,v 1.4 2004/12/21 23:15:21 olegk 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.lang.reflect.Constructor;
    35  import java.lang.reflect.InvocationTargetException;
    36  import java.lang.reflect.Method;
    37  import java.net.InetAddress;
    38  import java.net.Socket;
    39  import java.net.UnknownHostException;
    40
    41  import org.apache.commons.httpclient.ConnectTimeoutException;
    42
    43  /**
    44   * This helper class uses refelction in order to execute Socket methods
    45   * available in Java 1.4 and above
    46   *
    47   * @author Oleg Kalnichevski
    48   *
    49   * @since 3.0
    50   */
    51  public final class ReflectionSocketFactory {
    52
    53      private static boolean REFLECTION_FAILED = false;
    54
    55      private static Constructor INETSOCKETADDRESS_CONSTRUCTOR = null;
    56      private static Method SOCKETCONNECT_METHOD = null;
    57      private static Method SOCKETBIND_METHOD = null;
    58      private static Class SOCKETTIMEOUTEXCEPTION_CLASS = null;
    59
    60      private ReflectionSocketFactory() {
    61          super();
    62      }
    63
    64      /**
    65       * This method attempts to execute Socket method available since Java 1.4
    66       * using reflection. If the methods are not available or could not be executed
    67       * <tt>null</tt> is returned
    68       *
    69       * @param socketfactoryName name of the socket factory class
    70       * @param host the host name/IP
    71       * @param port the port on the host
    72       * @param localAddress the local host name/IP to bind the socket to
    73       * @param localPort the port on the local machine
    74       * @param timeout the timeout value to be used in milliseconds. If the socket cannot be
    75       *        completed within the given time limit, it will be abandoned
    76       *
    77       * @return a connected Socket
    78       *
    79       * @throws IOException if an I/O error occurs while creating the socket
    80       * @throws UnknownHostException if the IP address of the host cannot be
    81       * determined
    82       * @throws ConnectTimeoutException if socket cannot be connected within the
    83       *  given time limit
    84       *
    85       */
    86      public static Socket createSocket(
    87          final String socketfactoryName,
    88          final String host,
    89          final int port,
    90          final InetAddress localAddress,
    91          final int localPort,
    92          int timeout)
    93       throws IOException, UnknownHostException, ConnectTimeoutException
    94      {
    95          if (REFLECTION_FAILED) {
    96              //This is known to have failed before. Do not try it again
    97              return null;
    98          }
    99          // This code uses reflection to essentially do the following:
    100         //
    101         //  SocketFactory socketFactory = Class.forName(socketfactoryName).getDefault();
    102         //  Socket socket = socketFactory.createSocket();
    103         //  SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
    104         //  SocketAddress remoteaddr = new InetSocketAddress(host, port);
    105         //  socket.bind(localaddr);
    106         //  socket.connect(remoteaddr, timeout);
    107         //  return socket;
    108         try {
    109             Class socketfactoryClass = Class.forName(socketfactoryName);
    110             Method method = socketfactoryClass.getMethod("getDefault",
    111                 new Class[] {});
    112             Object socketfactory = method.invoke(null,
    113                 new Object[] {});
    114             method = socketfactoryClass.getMethod("createSocket",
    115                 new Class[] {});
    116             Socket socket = (Socket) method.invoke(socketfactory, new Object[] {});
    117
    118             if (INETSOCKETADDRESS_CONSTRUCTOR == null) {
    119                 Class addressClass = Class.forName("java.net.InetSocketAddress");
    120                 INETSOCKETADDRESS_CONSTRUCTOR = addressClass.getConstructor(
    121                     new Class[] { InetAddress.class, Integer.TYPE });
    122             }
    123
    124             Object remoteaddr = INETSOCKETADDRESS_CONSTRUCTOR.newInstance(
    125                 new Object[] { InetAddress.getByName(host), new Integer(port)});
    126
    127             Object localaddr = INETSOCKETADDRESS_CONSTRUCTOR.newInstance(
    128                     new Object[] { localAddress, new Integer(localPort)});
    129
    130             if (SOCKETCONNECT_METHOD == null) {
    131                 SOCKETCONNECT_METHOD = Socket.class.getMethod("connect",
    132                     new Class[] {Class.forName("java.net.SocketAddress"), Integer.TYPE});
    133             }
    134
    135             if (SOCKETBIND_METHOD == null) {
    136                 SOCKETBIND_METHOD = Socket.class.getMethod("bind",
    137                     new Class[] {Class.forName("java.net.SocketAddress")});
    138             }
    139             SOCKETBIND_METHOD.invoke(socket, new Object[] { localaddr});
    140             SOCKETCONNECT_METHOD.invoke(socket, new Object[] { remoteaddr, new Integer(timeout)});
    141             return socket;
    142         }
    143         catch (InvocationTargetException e) {
    144             Throwable cause = e.getTargetException();
    145             if (SOCKETTIMEOUTEXCEPTION_CLASS == null) {
    146                 try {
    147                     SOCKETTIMEOUTEXCEPTION_CLASS = Class.forName("java.net.SocketTimeoutException");
    148                 } catch (ClassNotFoundException ex) {
    149                     // At this point this should never happen. Really.
    150                     REFLECTION_FAILED = true;
    151                     return null;
    152                 }
    153             }
    154             if (SOCKETTIMEOUTEXCEPTION_CLASS.isInstance(cause)) {
    155                 throw new ConnectTimeoutException(
    156                     "The host did not accept the connection within timeout of "
    157                     + timeout + " ms", cause);
    158             }
    159             if (cause instanceof IOException) {
    160                 throw (IOException)cause;
    161             }
    162             return null;
    163         }
    164         catch (Exception e) {
    165             REFLECTION_FAILED = true;
    166             return null;
    167         }
    168     }
    169 }