commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject cvs commit: jakarta-commons/httpclient/src/test/org/apache/commons/httpclient TestHttpConnection.java TestHttpConnectionManager.java
Date Tue, 13 Apr 2004 21:47:29 GMT
olegk       2004/04/13 14:47:29

  Modified:    httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl
                        EasySSLProtocolSocketFactory.java
                        StrictSSLProtocolSocketFactory.java
               httpclient/src/java/org/apache/commons/httpclient
                        HttpConnection.java
               httpclient/src/java/org/apache/commons/httpclient/auth
                        AuthPolicy.java CredentialsProvider.java
               httpclient/src/java/org/apache/commons/httpclient/params
                        HttpConnectionManagerParams.java
               httpclient/src/java/org/apache/commons/httpclient/protocol
                        DefaultProtocolSocketFactory.java
                        ProtocolSocketFactory.java
                        SSLProtocolSocketFactory.java
               httpclient/src/test/org/apache/commons/httpclient
                        TestHttpConnection.java
                        TestHttpConnectionManager.java
  Added:       httpclient/src/java/org/apache/commons/httpclient/protocol
                        ControllerThreadSocketFactory.java
                        ReflectionSocketFactory.java
  Log:
  PR #28322 (Connection timeout logic redesign)
  
  Changelog:
  
  * CreateSocket method with timeout parameter added to the ProtocolSocketFactory
  interface
  
  * TimeoutController related code factored out of HttpConnection class and moved
  into ControllerThreadSocketFactory helper class
  
  * ReflectionSocketFactory helper class added. This factory encapsulates
  reflection code to call JDK 1.4 Socket#connect method if supported
  
  * All protocol socket factories now attempt to initially use
  ReflectionSocketFactory if required to create a socket within a given limit of
  time. If reflection fails protocol socket factories fall back onto the good ol'
  ControllerThreadSocketFactory
  
  Benefits:
  
  * HttpConnection code got a lot cleaner
  * When running in modern JREs expensive timeout controller thread per connection
  attempt is no longer needed
  * Ugly code intended to work around limitations of the older JREs is now
  confined to a few helper classes that can be easily thrown away once we move
  onto Java 1.4
  
  Contributed by Oleg Kalnichevski
  Reviewed by Michael Becke
  
  Revision  Changes    Path
  1.5       +64 -5     jakarta-commons/httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java
  
  Index: EasySSLProtocolSocketFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- EasySSLProtocolSocketFactory.java	22 Feb 2004 18:08:45 -0000	1.4
  +++ EasySSLProtocolSocketFactory.java	13 Apr 2004 21:47:28 -0000	1.5
  @@ -36,6 +36,11 @@
   import com.sun.net.ssl.SSLContext;
   import com.sun.net.ssl.TrustManager; 
   
  +import org.apache.commons.httpclient.ConnectTimeoutException;
  +import org.apache.commons.httpclient.HttpClientError;
  +import org.apache.commons.httpclient.params.HttpConnectionParams;
  +import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory;
  +import org.apache.commons.httpclient.protocol.ReflectionSocketFactory;
   import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
   import org.apache.commons.logging.Log; 
   import org.apache.commons.logging.LogFactory;
  @@ -64,6 +69,7 @@
       /** Log object for this class. */
       private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class);
   
  +    private static SSLContext SSL_CONTEXT_SINGLETON = null;
       /**
        * Constructor for EasySSLProtocolSocketFactory.
        * 
  @@ -81,21 +87,26 @@
           super();
       }
   
  -    private static SSLSocketFactory getEasySSLSocketFactory() {
  -        SSLContext context = null;
  +    private static SSLContext createEasySSLContext() {
           try {
  -            context = SSLContext.getInstance("SSL");
  +            SSLContext context = SSLContext.getInstance("SSL");
               context.init(
                 null, 
                 new TrustManager[] {new EasyX509TrustManager(null)}, 
                 null);
  +            return context;
           } catch (Exception e) {
               LOG.error(e.getMessage(), e);
  -            throw new RuntimeException(e.toString());
  +            throw new HttpClientError(e.toString());
           }
  -        return context.getSocketFactory();
       }
   
  +    private static SSLSocketFactory getEasySSLSocketFactory() {
  +        if (SSL_CONTEXT_SINGLETON == null) {
  +            SSL_CONTEXT_SINGLETON = createEasySSLContext();
  +        }
  +        return SSL_CONTEXT_SINGLETON.getSocketFactory();
  +    }
   
       /**
        * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
  @@ -114,6 +125,54 @@
               clientPort
           );
           return socket;
  +    }
  +
  +    /**
  +     * Attempts to get a new socket connection to the given host within the given time
limit.
  +     * <p>
  +     * This method employs several techniques to circumvent the limitations of older JREs
that 
  +     * do not support connect timeout. When running in JRE 1.4 or above reflection is used
to 
  +     * call Socket#connect(SocketAddress endpoint, int timeout) method. When executing
in older 
  +     * JREs a controller thread is executed. The controller thread attempts to create a
new socket
  +     * within the given limit of time. If socket constructor does not return until the
timeout 
  +     * expires, the controller terminates and throws an {@link ConnectTimeoutException}
  +     * </p>
  +     *  
  +     * @param host the host name/IP
  +     * @param port the port on the host
  +     * @param clientHost the local host name/IP to bind the socket to
  +     * @param clientPort the port on the local machine
  +     * @param params {@link HttpConnectionParams Http connection parameters}
  +     * 
  +     * @return Socket a new socket
  +     * 
  +     * @throws IOException if an I/O error occurs while creating the socket
  +     * @throws UnknownHostException if the IP address of the host cannot be
  +     * determined
  +     */
  +    public Socket createSocket(
  +        final String host,
  +        final int port,
  +        final InetAddress localAddress,
  +        final int localPort,
  +        final HttpConnectionParams params
  +    ) throws IOException, UnknownHostException, ConnectTimeoutException {
  +        if (params == null) {
  +            throw new IllegalArgumentException("Parameters may not be null");
  +        }
  +        int timeout = params.getConnectionTimeout();
  +        if (timeout == 0) {
  +            return createSocket(host, port, localAddress, localPort);
  +        } else {
  +            // To be eventually deprecated when migrated to Java 1.4 or above
  +            Socket socket = ReflectionSocketFactory.createSocket(
  +                "javax.net.ssl.SSLSocketFactory", host, port, localAddress, localPort,
timeout);
  +            if (socket == null) {
  +                socket = ControllerThreadSocketFactory.createSocket(
  +                    this, host, port, localAddress, localPort, timeout);
  +            }
  +            return socket;
  +        }
       }
   
       /**
  
  
  
  1.4       +56 -3     jakarta-commons/httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java
  
  Index: StrictSSLProtocolSocketFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- StrictSSLProtocolSocketFactory.java	22 Feb 2004 18:08:45 -0000	1.3
  +++ StrictSSLProtocolSocketFactory.java	13 Apr 2004 21:47:28 -0000	1.4
  @@ -54,6 +54,10 @@
   import javax.net.ssl.SSLSocketFactory;
   import javax.security.cert.X509Certificate;
   
  +import org.apache.commons.httpclient.ConnectTimeoutException;
  +import org.apache.commons.httpclient.params.HttpConnectionParams;
  +import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory;
  +import org.apache.commons.httpclient.protocol.ReflectionSocketFactory;
   import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
  @@ -159,6 +163,55 @@
           verifyHostname(sslSocket);
   
           return sslSocket;
  +    }
  +
  +    /**
  +     * Attempts to get a new socket connection to the given host within the given time
limit.
  +     * <p>
  +     * This method employs several techniques to circumvent the limitations of older JREs
that 
  +     * do not support connect timeout. When running in JRE 1.4 or above reflection is used
to 
  +     * call Socket#connect(SocketAddress endpoint, int timeout) method. When executing
in older 
  +     * JREs a controller thread is executed. The controller thread attempts to create a
new socket
  +     * within the given limit of time. If socket constructor does not return until the
timeout 
  +     * expires, the controller terminates and throws an {@link ConnectTimeoutException}
  +     * </p>
  +     *  
  +     * @param host the host name/IP
  +     * @param port the port on the host
  +     * @param clientHost the local host name/IP to bind the socket to
  +     * @param clientPort the port on the local machine
  +     * @param params {@link HttpConnectionParams Http connection parameters}
  +     * 
  +     * @return Socket a new socket
  +     * 
  +     * @throws IOException if an I/O error occurs while creating the socket
  +     * @throws UnknownHostException if the IP address of the host cannot be
  +     * determined
  +     */
  +    public Socket createSocket(
  +        final String host,
  +        final int port,
  +        final InetAddress localAddress,
  +        final int localPort,
  +        final HttpConnectionParams params
  +    ) throws IOException, UnknownHostException, ConnectTimeoutException {
  +        if (params == null) {
  +            throw new IllegalArgumentException("Parameters may not be null");
  +        }
  +        int timeout = params.getConnectionTimeout();
  +        if (timeout == 0) {
  +            return createSocket(host, port, localAddress, localPort);
  +        } else {
  +            // To be eventually deprecated when migrated to Java 1.4 or above
  +            SSLSocket sslSocket = (SSLSocket) ReflectionSocketFactory.createSocket(
  +                "javax.net.ssl.SSLSocketFactory", host, port, localAddress, localPort,
timeout);
  +            if (sslSocket == null) {
  +                sslSocket = (SSLSocket) ControllerThreadSocketFactory.createSocket(
  +                    this, host, port, localAddress, localPort, timeout);
  +            }
  +            verifyHostname(sslSocket);
  +            return sslSocket;
  +        }
       }
   
       /**
  
  
  
  1.88      +9 -85     jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java
  
  Index: HttpConnection.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java,v
  retrieving revision 1.87
  retrieving revision 1.88
  diff -u -r1.87 -r1.88
  --- HttpConnection.java	13 Apr 2004 18:20:23 -0000	1.87
  +++ HttpConnection.java	13 Apr 2004 21:47:28 -0000	1.88
  @@ -48,7 +48,6 @@
   import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
   import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
   import org.apache.commons.httpclient.util.EncodingUtil;
  -import org.apache.commons.httpclient.util.TimeoutController;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   
  @@ -641,41 +640,18 @@
           final int port = (proxyHostName == null) ? portNumber : proxyPortNumber;
           assertNotOpen();
           try {
  -            if (null == socket) {
  -
  -
  +            if (this.socket == null) {
                   usingSecureSocket = isSecure() && !isProxied();
  -
                   // use the protocol's socket factory unless this is a secure
                   // proxied connection
                   final ProtocolSocketFactory socketFactory =
                       (isSecure() && isProxied()
                               ? new DefaultProtocolSocketFactory()
                               : protocolInUse.getSocketFactory());
  -
  -                if (this.params.getConnectionTimeout() == 0) {
  -                    if (localAddress != null) {
  -                        socket = socketFactory.createSocket(host, port, localAddress, 0);
  -                    } else {
  -                        socket = socketFactory.createSocket(host, port);
  -                    }
  -                } else {
  -                    SocketTask task = new SocketTask() {
  -                        public void doit() throws IOException {
  -                            if (localAddress != null) {
  -                                setSocket(socketFactory.createSocket(host, port, localAddress,
0));
  -                            } else {
  -                                setSocket(socketFactory.createSocket(host, port));
  -                            }
  -                        }
  -                    };
  -                    TimeoutController.execute(task, this.params.getConnectionTimeout());
  -                    socket = task.getSocket();
  -                    if (task.exception != null) {
  -                        throw task.exception;
  -                    }
  -                }
  -
  +                this.socket = socketFactory.createSocket(
  +                            host, port, 
  +                            localAddress, 0,
  +                            this.params);
               }
   
               /*
  @@ -712,16 +688,6 @@
               // so close everything out
               closeSocketAndStreams();
               throw e;
  -        } catch (TimeoutController.TimeoutException e) {
  -            StringBuffer buffer = new StringBuffer();
  -            buffer.append("The host "); 
  -            buffer.append(host); 
  -            buffer.append(":"); 
  -            buffer.append(port); 
  -            buffer.append(" did not accept the connection within timeout of "); 
  -            buffer.append(this.params.getConnectionTimeout()); 
  -            buffer.append(" milliseconds"); 
  -            throw new ConnectTimeoutException(buffer.toString());
           }
       }
   
  @@ -1143,7 +1109,6 @@
       void setLocked(boolean locked) {
           this.locked = locked;
       }
  -
       // ------------------------------------------------------ Protected Methods
   
       /**
  @@ -1247,47 +1212,6 @@
        */
       public void setSendBufferSize(int sendBufferSize) throws SocketException {
           this.params.setSendBufferSize(sendBufferSize);
  -    }
  -
  -    /**
  -     * Helper class for wrapping socket based tasks.
  -     */
  -    private abstract class SocketTask implements Runnable {
  -
  -        /** The socket */
  -        private Socket socket;
  -        /** The exception */
  -        private IOException exception;
  -
  -        /**
  -         * Set the socket.
  -         * @param newSocket The new socket.
  -         */
  -        protected void setSocket(final Socket newSocket) {
  -            socket = newSocket;
  -        }
  -
  -        /**
  -         * Return the socket.
  -         * @return Socket The socket.
  -         */
  -        protected Socket getSocket() {
  -            return socket;
  -        }
  -        /**
  -         * Perform the logic.
  -         * @throws IOException If an IO problem occurs
  -         */
  -        public abstract void doit() throws IOException;
  -
  -        /** Execute the logic in this object and keep track of any exceptions. */
  -        public void run() {
  -            try {
  -                doit();
  -            } catch (IOException e) {
  -                exception = e;
  -            }
  -        }
       }
   
       /**
  
  
  
  1.4       +5 -5      jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthPolicy.java
  
  Index: AuthPolicy.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthPolicy.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- AuthPolicy.java	22 Feb 2004 18:08:47 -0000	1.3
  +++ AuthPolicy.java	13 Apr 2004 21:47:28 -0000	1.4
  @@ -64,7 +64,7 @@
       /**
        * The key used to look up the list of IDs of supported {@link AuthScheme 
        * authentication schemes} in their order of preference. The scheme IDs are 
  -     * stored in a {@link Collection} as {@link java.lang.String}s. 
  +     * stored in a {@link java.util.Collection} as {@link java.lang.String}s. 
        * 
        * <p>
        * If several schemes are returned in the <tt>WWW-Authenticate</tt> 
  
  
  
  1.3       +7 -6      jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/CredentialsProvider.java
  
  Index: CredentialsProvider.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/CredentialsProvider.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CredentialsProvider.java	22 Feb 2004 18:08:47 -0000	1.2
  +++ CredentialsProvider.java	13 Apr 2004 21:47:28 -0000	1.3
  @@ -35,9 +35,10 @@
   
   /**
    * <p>
  - * Credentials provider interface can be used to provide {@link HttpMethod
  - * HTTP method} with a means to request authentication credentials if no
  - * credentials have been given or given credentials are incorrect. 
  + * Credentials provider interface can be used to provide {@link 
  + * org.apache.commons.httpclient.HttpMethod HTTP method} with a means 
  + * to request authentication credentials if no credentials have been given 
  + * or given credentials are incorrect. 
    * </p>
    * 
    * @author Ortwin Glueck
  
  
  
  1.4       +6 -6      jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/params/HttpConnectionManagerParams.java
  
  Index: HttpConnectionManagerParams.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/params/HttpConnectionManagerParams.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- HttpConnectionManagerParams.java	22 Feb 2004 18:08:48 -0000	1.3
  +++ HttpConnectionManagerParams.java	13 Apr 2004 21:47:28 -0000	1.4
  @@ -45,7 +45,7 @@
   public class HttpConnectionManagerParams extends HttpConnectionParams {
   
       /** 
  -     * Defines the maximum number of connections allowed per host 
  +     * Defines the maximum number of connections allowed per host. 
        * <p>
        * This parameter expects a value of type {@link Integer}.
        * </p>
  @@ -53,7 +53,7 @@
       public static String MAX_HOST_CONNECTIONS = "http.connection-manager.max-per-host";
   
       /** 
  -     * Defines the maximum number of connections allowed overall 
  +     * Defines the maximum number of connections allowed overall.
        * <p>
        * This parameter expects a value of type {@link Integer}.
        * </p>
  
  
  
  1.8       +59 -6     jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/DefaultProtocolSocketFactory.java
  
  Index: DefaultProtocolSocketFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/DefaultProtocolSocketFactory.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- DefaultProtocolSocketFactory.java	22 Feb 2004 18:08:49 -0000	1.7
  +++ DefaultProtocolSocketFactory.java	13 Apr 2004 21:47:28 -0000	1.8
  @@ -36,6 +36,9 @@
   import java.net.Socket;
   import java.net.UnknownHostException;
   
  +import org.apache.commons.httpclient.ConnectTimeoutException;
  +import org.apache.commons.httpclient.params.HttpConnectionParams;
  +
   /**
    * The default class for creating protocol sockets.  This class just uses the
    * {@link java.net.Socket socket} constructors.
  @@ -72,10 +75,60 @@
       public Socket createSocket(
           String host,
           int port,
  -        InetAddress clientHost,
  -        int clientPort
  +        InetAddress localAddress,
  +        int localPort
       ) throws IOException, UnknownHostException {
  -        return new Socket(host, port, clientHost, clientPort);
  +        return new Socket(host, port, localAddress, localPort);
  +    }
  +    
  +    /**
  +     * Attempts to get a new socket connection to the given host within the given time
limit.
  +     * <p>
  +     * This method employs several techniques to circumvent the limitations of older JREs
that 
  +     * do not support connect timeout. When running in JRE 1.4 or above reflection is used
to 
  +     * call Socket#connect(SocketAddress endpoint, int timeout) method. When executing
in older 
  +     * JREs a controller thread is executed. The controller thread attempts to create a
new socket
  +     * within the given limit of time. If socket constructor does not return until the
timeout 
  +     * expires, the controller terminates and throws an {@link ConnectTimeoutException}
  +     * </p>
  +     *  
  +     * @param host the host name/IP
  +     * @param port the port on the host
  +     * @param localAddress the local host name/IP to bind the socket to
  +     * @param localPort the port on the local machine
  +     * @param params {@link HttpConnectionParams Http connection parameters}
  +     * 
  +     * @return Socket a new socket
  +     * 
  +     * @throws IOException if an I/O error occurs while creating the socket
  +     * @throws UnknownHostException if the IP address of the host cannot be
  +     * determined
  +     * @throws ConnectTimeoutException if socket cannot be connected within the
  +     *  given time limit
  +     */
  +    public Socket createSocket(
  +        final String host,
  +        final int port,
  +        final InetAddress localAddress,
  +        final int localPort,
  +        final HttpConnectionParams params
  +    ) throws IOException, UnknownHostException, ConnectTimeoutException {
  +        if (params == null) {
  +            throw new IllegalArgumentException("Parameters may not be null");
  +        }
  +        int timeout = params.getConnectionTimeout();
  +        if (timeout == 0) {
  +            return createSocket(host, port, localAddress, localPort);
  +        } else {
  +            // To be eventually deprecated when migrated to Java 1.4 or above
  +            Socket socket = ReflectionSocketFactory.createSocket(
  +                "javax.net.SocketFactory", host, port, localAddress, localPort, timeout);
  +            if (socket == null) {
  +                socket = ControllerThreadSocketFactory.createSocket(
  +                    this, host, port, localAddress, localPort, timeout);
  +            }
  +            return socket;
  +        }
       }
   
       /**
  
  
  
  1.8       +35 -7     jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ProtocolSocketFactory.java
  
  Index: ProtocolSocketFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ProtocolSocketFactory.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ProtocolSocketFactory.java	22 Feb 2004 18:08:49 -0000	1.7
  +++ ProtocolSocketFactory.java	13 Apr 2004 21:47:28 -0000	1.8
  @@ -36,6 +36,9 @@
   import java.net.Socket;
   import java.net.UnknownHostException;
   
  +import org.apache.commons.httpclient.ConnectTimeoutException;
  +import org.apache.commons.httpclient.params.HttpConnectionParams;
  +
   /**
    * A factory for creating Sockets.
    * 
  @@ -59,8 +62,8 @@
        * 
        * @param host the host name/IP
        * @param port the port on the host
  -     * @param clientHost the local host name/IP to bind the socket to
  -     * @param clientPort the port on the local machine
  +     * @param localAddress the local host name/IP to bind the socket to
  +     * @param localPort the port on the local machine
        * 
        * @return Socket a new socket
        * 
  @@ -71,9 +74,34 @@
       Socket createSocket(
           String host, 
           int port, 
  -        InetAddress clientHost, 
  -        int clientPort
  +        InetAddress localAddress, 
  +        int localPort
       ) throws IOException, UnknownHostException;
  +
  +    /**
  +     * Gets a new socket connection to the given host.
  +     * 
  +     * @param host the host name/IP
  +     * @param port the port on the host
  +     * @param localAddress the local host name/IP to bind the socket to
  +     * @param localPort the port on the local machine
  +     * @param params {@link HttpConnectionParams Http connection parameters}
  +     * 
  +     * @return Socket a new socket
  +     * 
  +     * @throws IOException if an I/O error occurs while creating the socket
  +     * @throws UnknownHostException if the IP address of the host cannot be
  +     * determined
  +     * @throws ConnectTimeoutException if socket cannot be connected within the
  +     *  given time limit
  +     */
  +    Socket createSocket(
  +        String host, 
  +        int port, 
  +        InetAddress localAddress, 
  +        int localPort,
  +        HttpConnectionParams params
  +    ) throws IOException, UnknownHostException, ConnectTimeoutException;
   
       /**
        * Gets a new socket connection to the given host.
  
  
  
  1.8       +54 -3     jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.java
  
  Index: SSLProtocolSocketFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- SSLProtocolSocketFactory.java	22 Feb 2004 18:08:49 -0000	1.7
  +++ SSLProtocolSocketFactory.java	13 Apr 2004 21:47:28 -0000	1.8
  @@ -38,6 +38,9 @@
   
   import javax.net.ssl.SSLSocketFactory;
   
  +import org.apache.commons.httpclient.ConnectTimeoutException;
  +import org.apache.commons.httpclient.params.HttpConnectionParams;
  +
   /**
    * A SecureProtocolSocketFactory that uses JSSE to create sockets.
    * 
  @@ -83,6 +86,54 @@
               clientHost,
               clientPort
           );
  +    }
  +
  +    /**
  +     * Attempts to get a new socket connection to the given host within the given time
limit.
  +     * <p>
  +     * This method employs several techniques to circumvent the limitations of older JREs
that 
  +     * do not support connect timeout. When running in JRE 1.4 or above reflection is used
to 
  +     * call Socket#connect(SocketAddress endpoint, int timeout) method. When executing
in older 
  +     * JREs a controller thread is executed. The controller thread attempts to create a
new socket
  +     * within the given limit of time. If socket constructor does not return until the
timeout 
  +     * expires, the controller terminates and throws an {@link ConnectTimeoutException}
  +     * </p>
  +     *  
  +     * @param host the host name/IP
  +     * @param port the port on the host
  +     * @param localAddress the local host name/IP to bind the socket to
  +     * @param localPort the port on the local machine
  +     * @param params {@link HttpConnectionParams Http connection parameters}
  +     * 
  +     * @return Socket a new socket
  +     * 
  +     * @throws IOException if an I/O error occurs while creating the socket
  +     * @throws UnknownHostException if the IP address of the host cannot be
  +     * determined
  +     */
  +    public Socket createSocket(
  +        final String host,
  +        final int port,
  +        final InetAddress localAddress,
  +        final int localPort,
  +        final HttpConnectionParams params
  +    ) throws IOException, UnknownHostException, ConnectTimeoutException {
  +        if (params == null) {
  +            throw new IllegalArgumentException("Parameters may not be null");
  +        }
  +        int timeout = params.getConnectionTimeout();
  +        if (timeout == 0) {
  +            return createSocket(host, port, localAddress, localPort);
  +        } else {
  +            // To be eventually deprecated when migrated to Java 1.4 or above
  +            Socket socket = ReflectionSocketFactory.createSocket(
  +                "javax.net.ssl.SSLSocketFactory", host, port, localAddress, localPort,
timeout);
  +            if (socket == null) {
  +                socket = ControllerThreadSocketFactory.createSocket(
  +                    this, host, port, localAddress, localPort, timeout);
  +            }
  +            return socket;
  +        }
       }
   
       /**
  
  
  
  1.1                  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ControllerThreadSocketFactory.java
  
  Index: ControllerThreadSocketFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ControllerThreadSocketFactory.java,v
1.1 2004/04/13 21:47:28 olegk Exp $
   * $Revision: 1.1 $
   * $Date: 2004/04/13 21:47:28 $
   *
   * ====================================================================
   *
   *  Copyright 2002-2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  package org.apache.commons.httpclient.protocol;
  
  import java.io.IOException;
  import java.net.InetAddress;
  import java.net.Socket;
  import java.net.UnknownHostException;
  
  import org.apache.commons.httpclient.ConnectTimeoutException;
  import org.apache.commons.httpclient.util.TimeoutController;
  
  /**
   * This helper class is intedned to help work around the limitation of older Java versions
   * (older than 1.4) that prevents from specifying a connection timeout when creating a
   * socket. This factory executes a controller thread overssing the process of socket 
   * initialisation. If the socket constructor cannot be created within the specified time
   * limit, the controller terminates and throws an {@link ConnectTimeoutException} 
   * 
   * @author Ortwin Glueck
   * @author Oleg Kalnichevski
   * 
   * @since 3.0
   */
  public final class ControllerThreadSocketFactory {
  
      private ControllerThreadSocketFactory() {
          super();
      }
  
      /**
       * This method spawns a controller thread overseeing the process of socket 
       * initialisation. If the socket constructor cannot be created within the specified
time
       * limit, the controller terminates and throws an {@link ConnectTimeoutException}
       * 
       * @param host the host name/IP
       * @param port the port on the host
       * @param localAddress the local host name/IP to bind the socket to
       * @param localPort the port on the local machine
       * @param timeout the timeout value to be used in milliseconds. If the socket cannot
be
       *        completed within the given time limit, it will be abandoned
       * 
       * @return a connected Socket
       * 
       * @throws IOException if an I/O error occurs while creating the socket
       * @throws UnknownHostException if the IP address of the host cannot be
       * determined
       * @throws ConnectTimeoutException if socket cannot be connected within the
       *  given time limit
       * 
       */
      public static Socket createSocket(
          final ProtocolSocketFactory socketfactory, 
          final String host,
          final int port,
          final InetAddress localAddress,
          final int localPort,
          int timeout)
       throws IOException, UnknownHostException, ConnectTimeoutException
      {
              SocketTask task = new SocketTask() {
                  public void doit() throws IOException {
                      setSocket(socketfactory.createSocket(host, port, localAddress, localPort));
                  }                 
              };
              try {
                  TimeoutController.execute(task, timeout);
              } catch (TimeoutController.TimeoutException e) {
                  throw new ConnectTimeoutException(
                      "The host did not accept the connection within timeout of " 
                      + timeout + " ms");
              }
              Socket socket = task.getSocket();
              if (task.exception != null) {
                  throw task.exception;
              }
              return socket;
      }
  
      public static Socket createSocket(final SocketTask task, int timeout)
       throws IOException, UnknownHostException, ConnectTimeoutException
      {
              try {
                  TimeoutController.execute(task, timeout);
              } catch (TimeoutController.TimeoutException e) {
                  throw new ConnectTimeoutException(
                      "The host did not accept the connection within timeout of " 
                      + timeout + " ms");
              }
              Socket socket = task.getSocket();
              if (task.exception != null) {
                  throw task.exception;
              }
              return socket;
      }
  
      /**
      * Helper class for wrapping socket based tasks.
      */
      public static abstract class SocketTask implements Runnable {
          /** The socket */
          private Socket socket;
          /** The exception */
          private IOException exception;
  
          /**
           * Set the socket.
           * @param newSocket The new socket.
           */
          protected void setSocket(final Socket newSocket) {
              socket = newSocket;
          }
  
          /**
           * Return the socket.
           * @return Socket The socket.
           */
          protected Socket getSocket() {
              return socket;
          }
          /**
           * Perform the logic.
           * @throws IOException If an IO problem occurs
           */
          public abstract void doit() throws IOException;
  
          /** Execute the logic in this object and keep track of any exceptions. */
          public void run() {
              try {
                  doit();
              } catch (IOException e) {
                  exception = e;
              }
          }
      }
  }
  
  
  
  1.1                  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ReflectionSocketFactory.java
  
  Index: ReflectionSocketFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ReflectionSocketFactory.java,v
1.1 2004/04/13 21:47:28 olegk Exp $
   * $Revision: 1.1 $
   * $Date: 2004/04/13 21:47:28 $
   *
   * ====================================================================
   *
   *  Copyright 2002-2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  package org.apache.commons.httpclient.protocol;
  
  import java.io.IOException;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.net.InetAddress;
  import java.net.Socket;
  import java.net.UnknownHostException;
  
  import org.apache.commons.httpclient.ConnectTimeoutException;
  
  /**
   * This helper class uses refelction in order to execute Socket methods
   * available in Java 1.4 and above  
   * 
   * @author Oleg Kalnichevski
   * 
   * @since 3.0
   */
  public final class ReflectionSocketFactory {
  
      private static boolean REFLECTION_FAILED = false;
      
      private static Constructor INETSOCKETADDRESS_CONSTRUCTOR = null;
      private static Method SOCKETCONNECT_METHOD = null;
      private static Class SOCKETTIMEOUTEXCEPTION_CLASS = null;
  
      private ReflectionSocketFactory() {
          super();
      }
  
      /**
       * This method attempts to execute Socket method available since Java 1.4
       * using reflection. If the methods are not available or could not be executed
       * <tt>null</tt> is returned
       *   
       * @param host the host name/IP
       * @param port the port on the host
       * @param localAddress the local host name/IP to bind the socket to
       * @param localPort the port on the local machine
       * @param timeout the timeout value to be used in milliseconds. If the socket cannot
be
       *        completed within the given time limit, it will be abandoned
       * 
       * @return a connected Socket
       * 
       * @throws IOException if an I/O error occurs while creating the socket
       * @throws UnknownHostException if the IP address of the host cannot be
       * determined
       * @throws ConnectTimeoutException if socket cannot be connected within the
       *  given time limit
       * 
       */
      public static Socket createSocket(
          final String socketfactoryName, 
          final String host,
          final int port,
          final InetAddress localAddress,
          final int localPort,
          int timeout)
       throws IOException, UnknownHostException, ConnectTimeoutException
      {
          if (REFLECTION_FAILED) {
              //This is known to have failed before. Do not try it again
              return null;
          }
          // This code uses reflection to essentially do the following:
          //
          //  SocketFactory socketFactory = Class.forName(socketfactoryName).getDefault();
          //  Socket socket = socketFactory.createSocket();
          //  SocketAddress addr = new InetSocketAddress(host, port);
          //  socket.connect(addr, timeout);
          //  return socket;
          try {
              Class socketfactoryClass = Class.forName(socketfactoryName);
              Method method = socketfactoryClass.getMethod("getDefault", 
                  new Class[] {});
              Object socketfactory = method.invoke(null, 
                  new Object[] {});
              method = socketfactoryClass.getMethod("createSocket", 
                  new Class[] {});
              Socket socket = (Socket) method.invoke(socketfactory, new Object[] {});
              
              if (INETSOCKETADDRESS_CONSTRUCTOR == null) {
                  Class addressClass = Class.forName("java.net.InetSocketAddress");
                  INETSOCKETADDRESS_CONSTRUCTOR = addressClass.getConstructor(
                      new Class[] { String.class, Integer.TYPE });
              }
                  
              Object addr = INETSOCKETADDRESS_CONSTRUCTOR.newInstance(
                  new Object[] { host, new Integer(port)});
  
              if (SOCKETCONNECT_METHOD == null) {
                  SOCKETCONNECT_METHOD = Socket.class.getMethod("connect", 
                      new Class[] {Class.forName("java.net.SocketAddress"), Integer.TYPE});
              }
  
              SOCKETCONNECT_METHOD.invoke(socket, 
                  new Object[] { addr, new Integer(timeout)});
  
              return socket;
          }
          catch (InvocationTargetException e) {
              Throwable cause = e.getTargetException(); 
              if (SOCKETTIMEOUTEXCEPTION_CLASS == null) {
                  try {
                      SOCKETTIMEOUTEXCEPTION_CLASS = Class.forName("java.net.SocketTimeoutException");
                  } catch (ClassNotFoundException ex) {
                      // At this point this should never happen. Really.
                      REFLECTION_FAILED = true;
                      return null;
                  }
              }
              if (SOCKETTIMEOUTEXCEPTION_CLASS.isInstance(cause)) {
                  throw new ConnectTimeoutException(
                      "The host did not accept the connection within timeout of " 
                      + timeout + " ms", cause);
              }
              if (cause instanceof IOException) {
                  throw (IOException)cause;
              }
              return null;
          }
          catch (Exception e) {
              REFLECTION_FAILED = true;
              return null;
          }
      }
  }
  
  
  
  1.16      +30 -3     jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnection.java
  
  Index: TestHttpConnection.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnection.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- TestHttpConnection.java	22 Feb 2004 18:08:49 -0000	1.15
  +++ TestHttpConnection.java	13 Apr 2004 21:47:29 -0000	1.16
  @@ -41,8 +41,10 @@
   import junit.framework.TestSuite;
   
   import org.apache.commons.httpclient.methods.GetMethod;
  +import org.apache.commons.httpclient.params.HttpConnectionParams;
   import org.apache.commons.httpclient.protocol.Protocol;
   import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
  +import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory;
   
   /**
    *
  @@ -189,8 +191,8 @@
           public Socket createSocket(
               String host,
               int port,
  -            InetAddress clientHost,
  -            int clientPort
  +            InetAddress localAddress,
  +            int localPort
           ) throws IOException, UnknownHostException {
               
               synchronized (this) {
  @@ -198,7 +200,32 @@
                       this.wait(delay);
                   } catch (InterruptedException e) {}
               }
  -            return realFactory.createSocket(host, port, clientHost, clientPort);
  +            return realFactory.createSocket(host, port, localAddress, localPort);
  +        }
  +
  +        public Socket createSocket(
  +            final String host,
  +            final int port,
  +            final InetAddress localAddress,
  +            final int localPort,
  +            final HttpConnectionParams params
  +        ) throws IOException, UnknownHostException {
  +            
  +            if (params == null) {
  +                throw new IllegalArgumentException("Parameters may not be null");
  +            }
  +            int timeout = params.getConnectionTimeout();
  +            ControllerThreadSocketFactory.SocketTask task = new ControllerThreadSocketFactory.SocketTask()
{
  +                public void doit() throws IOException {
  +                    synchronized (this) {
  +                        try {
  +                            this.wait(delay);
  +                        } catch (InterruptedException e) {}
  +                    }
  +                    setSocket(realFactory.createSocket(host, port, localAddress, localPort));
  +                }
  +            };
  +            return ControllerThreadSocketFactory.createSocket(task, timeout);
           }
   
           public Socket createSocket(String host, int port)
  
  
  
  1.21      +10 -4     jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java
  
  Index: TestHttpConnectionManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- TestHttpConnectionManager.java	8 Apr 2004 22:25:11 -0000	1.20
  +++ TestHttpConnectionManager.java	13 Apr 2004 21:47:29 -0000	1.21
  @@ -41,6 +41,7 @@
   
   import org.apache.commons.httpclient.methods.GetMethod;
   import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
  +import org.apache.commons.httpclient.params.HttpConnectionParams;
   import org.apache.commons.httpclient.protocol.Protocol;
   import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
   import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
  @@ -683,6 +684,11 @@
               throw new IllegalStateException("createSocket() should never have been called.");
           }
           
  +        public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort,

  +            HttpConnectionParams params)
  +            throws IOException, UnknownHostException {
  +            throw new IllegalStateException("createSocket() should never have been called.");
  +        }
       }
       
       static class GetConnectionThread extends Thread {
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message