1   /*
2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java,v 1.23 2004/07/17 18:58:33 mbecke Exp $
3    * $Revision: 155418 $
4    * $Date: 2005-02-26 08:01:52 -0500 (Sat, 26 Feb 2005) $
5    * ====================================================================
6    *
7    *  Copyright 1999-2004 The Apache Software Foundation
8    *
9    *  Licensed under the Apache License, Version 2.0 (the "License");
10   *  you may not use this file except in compliance with the License.
11   *  You may obtain a copy of the License at
12   *
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   *
15   *  Unless required by applicable law or agreed to in writing, software
16   *  distributed under the License is distributed on an "AS IS" BASIS,
17   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   *  See the License for the specific language governing permissions and
19   *  limitations under the License.
20   * ====================================================================
21   *
22   * This software consists of voluntary contributions made by many
23   * individuals on behalf of the Apache Software Foundation.  For more
24   * information on the Apache Software Foundation, please see
25   * <http://www.apache.org/>.
26   *
27   * [Additional notices, if required by prior licensing conditions]
28   *
29   */
30  
31  package org.apache.commons.httpclient;
32  
33  import java.io.IOException;
34  import java.lang.ref.WeakReference;
35  import java.net.InetAddress;
36  import java.net.Socket;
37  import java.net.UnknownHostException;
38  
39  import junit.framework.Test;
40  import junit.framework.TestSuite;
41  
42  import org.apache.commons.httpclient.methods.GetMethod;
43  import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
44  import org.apache.commons.httpclient.params.HttpConnectionParams;
45  import org.apache.commons.httpclient.protocol.Protocol;
46  import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
47  import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
48  
49  /***
50   * Unit tests for {@link HttpConnectionManager}.
51   *
52   * @author Marc A. Saegesser
53   * @version $Id: TestHttpConnectionManager.java 155418 2005-02-26 13:01:52Z dirkv $
54   */
55  public class TestHttpConnectionManager extends TestLocalHostBase {
56  
57      // ------------------------------------------------------------ Constructor
58      public TestHttpConnectionManager(String testName) {
59          super(testName);
60      }
61  
62      // ------------------------------------------------------------------- Main
63      public static void main(String args[]) {
64          String[] testCaseName = { TestHttpConnectionManager.class.getName() };
65          junit.textui.TestRunner.main(testCaseName);
66      }
67  
68      // ------------------------------------------------------- TestCase Methods
69  
70      public static Test suite() {
71          return new TestSuite(TestHttpConnectionManager.class);
72      }
73  
74  
75      // ----------------------------------------------------------- Test Methods
76  
77      /***
78       * Test that the ConnectMethod correctly releases connections when
79       * CONNECT fails.
80       */
81      public void testConnectMethodFailureRelease() throws Exception {
82          
83          MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
84          mgr.getParams().setIntParameter(
85              HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
86          HttpClient client = createHttpClient(mgr);
87          
88          // we're going to execute a connect method against the localhost, assuming
89          // that CONNECT is not supported.  This should test the fakeResponse()
90          // code on HttpMethodBase.
91          client.getHostConfiguration().setProxy(getHost(), getPort());
92          // we must set the host to a secure destination or the CONNECT method
93          // will not be used
94          client.getHostConfiguration().setHost(
95              "notARealHost", 
96              1234, 
97              new Protocol(
98                  "https", 
99                  (ProtocolSocketFactory)new FakeSecureProtocolSocketFactory(), 
100                 443)
101         );
102         
103         GetMethod get = new GetMethod("/");
104         try {
105             assertTrue(client.executeMethod(get) != 200);
106         } catch (IOException e) {
107             e.printStackTrace();
108             fail("Error executing connect: " + e);
109         }
110 
111         // this should calling releaseConnection() releases the connection
112         try {
113             get.releaseConnection();
114             mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
115         } catch (ConnectTimeoutException e1) {
116             fail("Connection should have been available.");
117         }
118         
119         get = new GetMethod("/");
120         
121         try {
122             assertTrue(client.executeMethod(get) != 200);
123         } catch (IOException e) {
124             e.printStackTrace();
125             fail("Error executing connect: " + e);
126         }
127 
128         // make sure reading the response fully releases the connection        
129         try {
130             get.getResponseBodyAsString();
131             mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
132         } catch (ConnectTimeoutException e1) {
133             fail("Connection should have been available.");
134         }     
135         
136         get = new GetMethod("/");
137         
138         try {
139             assertTrue(client.executeMethod(get) != 200);
140         } catch (IOException e) {
141             e.printStackTrace();
142             fail("Error executing connect: " + e);
143         }
144 
145         // make sure closing the output stream releases the connection        
146         try {
147             get.getResponseBodyAsStream().close();
148             mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
149         } catch (ConnectTimeoutException e) {
150             fail("Connection should have been available.");
151         } catch (IOException e) {
152             e.printStackTrace();
153             fail("Close connection failed: " + e);   
154         }
155     }
156 
157     public void testGetConnection() {
158         MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
159 
160         HostConfiguration hostConfiguration = new HostConfiguration();
161         hostConfiguration.setHost("www.nosuchserver.com", 80, "http");
162 
163         // Create a new connection
164         HttpConnection conn = mgr.getConnection(hostConfiguration);
165         // Validate the connection properties
166         assertEquals("Host", "www.nosuchserver.com", conn.getHost());
167         assertEquals("Port", 80, conn.getPort());
168         // Release the connection
169         mgr.releaseConnection(conn);
170 
171         // Create a new connection
172         hostConfiguration.setHost("www.nosuchserver.com", -1, "https");
173         conn = mgr.getConnection(hostConfiguration);
174         // Validate the connection properties
175         assertEquals("Host", "www.nosuchserver.com", conn.getHost());
176         assertEquals("Port", 443, conn.getPort());
177         // Release the connection
178         mgr.releaseConnection(conn);
179 
180         // Create a new connection
181         hostConfiguration.setHost("www.nowhere.org", 8080, "http");
182         conn = mgr.getConnection(hostConfiguration);
183         // Validate the connection properties
184         assertEquals("Host", "www.nowhere.org", conn.getHost());
185         assertEquals("Port", 8080, conn.getPort());
186         // Release the connection
187         mgr.releaseConnection(conn);
188 
189     }
190 
191     public void testDroppedThread() throws Exception {
192 
193         MultiThreadedHttpConnectionManager mthcm = new MultiThreadedHttpConnectionManager();
194         HttpClient httpClient = createHttpClient(mthcm);
195         WeakReference wr = new WeakReference(mthcm);
196 
197         GetMethod method = new GetMethod("/");
198         httpClient.executeMethod(method);
199         method.releaseConnection();
200 
201         mthcm = null;
202         httpClient = null;
203         method = null;
204         
205         System.gc();
206 
207         // this sleep appears to be necessary in order to give the JVM
208         // time to clean up the miscellaneous pointers to the connection manager
209         try {
210             Thread.sleep(1000);
211         } catch (InterruptedException e) {
212             fail("shouldn't be interrupted.");
213         }
214 
215         Object connectionManager = wr.get();
216         assertNull("connectionManager should be null", connectionManager);
217     }    
218     
219     public void testWriteRequestReleaseConnection() {
220 
221         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
222         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
223 
224         HttpClient client = createHttpClient(connectionManager);
225         
226         GetMethod get = new GetMethod("/") {
227             protected boolean writeRequestBody(HttpState state, HttpConnection conn)
228                 throws IOException, HttpException {
229                 throw new IOException("Oh no!!");
230             }
231         };
232         
233         try {
234             client.executeMethod(get);
235             fail("An exception should have occurred.");
236         } catch (HttpException e) {
237             e.printStackTrace();
238             fail("HttpException should not have occurred: " + e);
239         } catch (IOException e) {
240             // expected
241         }
242         
243         try {
244             connectionManager.getConnectionWithTimeout(client.getHostConfiguration(), 1);
245         } catch (ConnectTimeoutException e) {
246             e.printStackTrace();
247             fail("Connection was not released: " + e);
248         }
249         
250     }
251     
252     public void testReleaseConnection() {
253 
254         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
255         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
256 
257         HttpClient client = createHttpClient(connectionManager);
258         // we shouldn't have to wait if a connection is available
259         client.getParams().setConnectionManagerTimeout(1);
260 
261         GetMethod getMethod = new GetMethod("/");
262 
263         try {
264             client.executeMethod(getMethod);
265         } catch (Exception e) {
266             fail("error reading from server: " + e);
267         }
268 
269         try {
270             // this should fail quickly since the connection has not been released
271             client.executeMethod(getMethod);
272             fail("a httpConnection should not be available");
273         } catch (ConnectTimeoutException e) {            
274         } catch (HttpException e) {
275             fail("error reading from server; " + e);
276         } catch (IOException e) {
277             e.printStackTrace();
278             fail("error reading from server; " + e);
279         }
280 
281         // this should release the connection
282         getMethod.releaseConnection();
283 
284         getMethod = new GetMethod("/");
285 
286         try {
287             // this should fail quickly if the connection has not been released
288             client.executeMethod(getMethod);
289         } catch (HttpException e) {
290             fail("httpConnection does not appear to have been released: " + e);
291         } catch (IOException e) {
292             fail("error reading from server; " + e);
293         }
294 
295     }
296 
297     /***
298      * Makes sure that a connection gets released after the content of the body
299      * is read.
300      */
301     public void testResponseAutoRelease() throws Exception  {
302 
303         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
304         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
305 
306         HttpClient client = createHttpClient(connectionManager);
307         // we shouldn't have to wait if a connection is available
308         client.getParams().setConnectionManagerTimeout( 1 );
309 
310         GetMethod getMethod = new GetMethod("/");
311 
312         try {
313             client.executeMethod(getMethod);
314         } catch (Exception e) {
315             fail("error reading from server: " + e);
316         }
317         
318         // this should release the connection
319         getMethod.getResponseBody();
320 
321         getMethod = new GetMethod("/");
322 
323         try {
324             // this should fail quickly if the connection has not been released
325             client.executeMethod(getMethod);
326         } catch (HttpException e) {
327             fail("httpConnection does not appear to have been released: " + e);
328         } catch (IOException e) {
329             fail("error reading from server; " + e);
330         }
331 
332     }
333     
334     /***
335      * Tests the MultiThreadedHttpConnectionManager's ability to reclaim unused 
336      * connections.
337      */
338     public void testConnectionReclaiming() {
339         
340         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
341         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
342         connectionManager.getParams().setMaxTotalConnections(1);
343 
344         HostConfiguration host1 = new HostConfiguration();
345         host1.setHost("host1", -1, "http");
346 
347         HostConfiguration host2 = new HostConfiguration();
348         host2.setHost("host2", -1, "http");
349 
350         HttpConnection connection = connectionManager.getConnection(host1);
351         // now release this connection
352         connection.releaseConnection();
353         connection = null;
354         
355         try {
356             // the connection from host1 should be reclaimed
357             connection = connectionManager.getConnectionWithTimeout(host2, 100);
358         } catch (ConnectTimeoutException e) {
359             e.printStackTrace();
360             fail("a httpConnection should have been available: " + e);
361         }        
362     }
363     
364     /***
365      * Tests that {@link MultiThreadedHttpConnectionManager#shutdownAll()} closes all resources
366      * and makes all connection mangers unusable.
367      */
368     public void testShutdownAll() {
369 
370         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
371         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
372         connectionManager.getParams().setMaxTotalConnections(1);
373 
374         HostConfiguration host1 = new HostConfiguration();
375         host1.setHost("host1", -1, "http");
376 
377         // hold on to the only connection
378         HttpConnection connection = connectionManager.getConnection(host1);
379 
380         // wait for a connection on another thread
381         GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
382         getConn.start();
383         
384         MultiThreadedHttpConnectionManager.shutdownAll();
385         
386         // now release this connection, this should close the connection, but have no other effect
387         connection.releaseConnection();
388         connection = null;
389         
390         try {
391             getConn.join();
392         } catch (InterruptedException e) {
393             e.printStackTrace();
394         }
395         
396         // this thread should have caught an exception without getting a connection
397         assertNull("Not connection should have been checked out", getConn.getConnection());
398         assertNotNull("There should have been an exception", getConn.getException());
399         
400         try {
401             connectionManager.getConnection(host1);
402             fail("An exception should have occurred");
403         } catch (Exception e) {
404             // this is expected
405         }
406     }
407         
408     /***
409      * Tests that {@link MultiThreadedHttpConnectionManager#shutdown()} closes all resources
410      * and makes the connection manger unusable.
411      */
412     public void testShutdown() {
413 
414         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
415         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
416         connectionManager.getParams().setMaxTotalConnections(1);
417 
418         HostConfiguration host1 = new HostConfiguration();
419         host1.setHost("host1", -1, "http");
420 
421         // hold on to the only connection
422         HttpConnection connection = connectionManager.getConnection(host1);
423 
424         // wait for a connection on another thread
425         GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
426         getConn.start();
427         
428         connectionManager.shutdown();
429         
430         // now release this connection, this should close the connection, but have no other effect
431         connection.releaseConnection();
432         connection = null;
433         
434         try {
435             getConn.join();
436         } catch (InterruptedException e) {
437             e.printStackTrace();
438         }
439         
440         // this thread should have caught an exception without getting a connection
441         assertNull("Not connection should have been checked out", getConn.getConnection());
442         assertNotNull("There should have been an exception", getConn.getException());
443         
444         try {
445             connectionManager.getConnection(host1);
446             fail("An exception should have occurred");
447         } catch (Exception e) {
448             // this is expected
449         }
450     }
451     
452     /***
453      * Tests the MultiThreadedHttpConnectionManager's ability to restrict the maximum number 
454      * of connections.
455      */    
456     public void testMaxConnections() {
457         
458         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
459         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
460         connectionManager.getParams().setMaxTotalConnections(2);
461 
462         HostConfiguration host1 = new HostConfiguration();
463         host1.setHost("host1", -1, "http");
464 
465         HostConfiguration host2 = new HostConfiguration();
466         host2.setHost("host2", -1, "http");
467 
468         HttpConnection connection1 = connectionManager.getConnection(host1);
469         HttpConnection connection2 = connectionManager.getConnection(host2);
470     
471         try {
472             // this should fail quickly since the connection has not been released
473             connectionManager.getConnectionWithTimeout(host2, 100);
474             fail("a httpConnection should not be available");
475         } catch (ConnectTimeoutException e) {
476             // this should throw an exception
477         }
478         
479         // release one of the connections
480         connection2.releaseConnection();
481         connection2 = null;
482         
483         try {
484             // there should be a connection available now
485             connection2 = connectionManager.getConnectionWithTimeout(host2, 100);
486         } catch (ConnectTimeoutException e) {
487             e.printStackTrace();
488             fail("a httpConnection should have been available: " + e);
489         }
490     }    
491 
492     public void testHostReusePreference() {
493         
494         final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
495         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
496         connectionManager.getParams().setMaxTotalConnections(1);
497 
498         final HostConfiguration host1 = new HostConfiguration();
499         host1.setHost("host1", -1, "http");
500 
501         final HostConfiguration host2 = new HostConfiguration();
502         host2.setHost("host2", -1, "http");
503 
504         HttpConnection connection = connectionManager.getConnection(host1);
505 
506         GetConnectionThread getHost1 = new GetConnectionThread(host1, connectionManager, 200);
507         GetConnectionThread getHost2 = new GetConnectionThread(host2, connectionManager, 200);
508         
509         getHost2.start();
510         getHost1.start();
511         
512         // give the threads some time to startup
513         try {
514             Thread.sleep(100);
515         } catch (InterruptedException e1) {
516             e1.printStackTrace();
517         }
518             
519         // after the connection to host1 is released it should be given to getHost1
520         connection.releaseConnection();
521         connection = null;
522 
523         try {
524             getHost1.join();
525             getHost2.join();
526         } catch (InterruptedException e) {
527             e.printStackTrace();
528         }
529 
530         assertNotSame(
531             "Connection should have been given to someone", 
532             getHost1.getConnection(),
533             getHost2.getConnection()
534         );        
535         assertNotNull("Connection should have been given to host1", getHost1.getConnection());
536         assertNull("Connection should NOT have been given to host2", getHost2.getConnection());
537         
538     } 
539     
540     public void testMaxConnectionsPerServer() {
541      
542         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
543         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
544 
545         HttpClient client = createHttpClient(connectionManager);
546         // we shouldn't have to wait if a connection is available
547         client.getParams().setConnectionManagerTimeout( 1 );
548 
549         GetMethod getMethod = new GetMethod("/");
550 
551         try {
552             client.executeMethod(getMethod);
553         } catch (Exception e) {
554             fail("error reading from server: " + e);
555         }
556 
557         GetMethod getMethod2 = new GetMethod("/");
558 
559         try {
560             // this should fail quickly since the connection has not been released
561             client.executeMethod(getMethod2);
562             fail("a httpConnection should not be available");
563         } catch (ConnectTimeoutException e) {
564         } catch (HttpException e) {
565             fail("error reading from server; " + e);
566         } catch (IOException e) {
567             fail("error reading from server; " + e);
568         }
569                 
570     }
571     
572     public void testDeleteClosedConnections() {
573         
574         MultiThreadedHttpConnectionManager manager = new MultiThreadedHttpConnectionManager();
575 
576         HostConfiguration hostConfig = new HostConfiguration();
577         
578         configureHostConfiguration(hostConfig);
579         
580         HttpConnection conn = manager.getConnection(hostConfig);
581         
582         assertEquals("connectionsInPool", manager.getConnectionsInPool(), 1);
583         assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(hostConfig), 1);
584         
585         conn.close();
586         conn.releaseConnection();
587 
588         assertEquals("connectionsInPool", manager.getConnectionsInPool(), 1);
589         assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(hostConfig), 1);
590 
591         manager.deleteClosedConnections();
592         
593         assertEquals("connectionsInPool", manager.getConnectionsInPool(), 0);
594         assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(hostConfig), 0);
595     }
596     
597     public void testReclaimUnusedConnection() {
598 
599         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
600         connectionManager.getParams().setIntParameter(
601             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
602 
603         HttpClient client = createHttpClient(connectionManager);
604         // we shouldn't have to wait if a connection is available
605         client.getParams().setConnectionManagerTimeout( 30000 );
606 
607         GetMethod getMethod = new GetMethod("/");
608 
609         try {
610             client.executeMethod(getMethod);
611         } catch (Exception e) {
612             fail("error reading from server: " + e);
613         }
614 
615         getMethod = new GetMethod("/");
616         
617         Runtime.getRuntime().gc();
618 
619         try {
620             // we didn't explicitly release the connection, but it should be 
621             // reclaimed by the garbage collector, we hope:)
622             client.executeMethod(getMethod);
623         } catch (HttpException e) {
624             fail("httpConnection does not appear to have been reclaimed by the GC: " + e);
625         } catch (IOException e) {
626             fail("error reading from server; " + e);
627         }
628 
629     }
630     
631     public void testGetFromMultipleThreads() {
632         
633         HttpClient client = createHttpClient(new MultiThreadedHttpConnectionManager());
634         ExecuteMethodThread[] threads = new ExecuteMethodThread[10];
635         
636         for (int i = 0; i < threads.length; i++) {
637             GetMethod method = new GetMethod("/");
638             method.setFollowRedirects(true);
639             
640             threads[i] = new ExecuteMethodThread(method, client);
641             threads[i].start();
642         }
643         
644         for (int i = 0; i < threads.length; i++) {
645             try {
646                 // wait until this thread finishes. we'll give it 10 seconds,
647                 // but it shouldn't take that long
648                 threads[i].join(10000);
649             } catch (InterruptedException e) {
650             }
651             // make sure an exception did not occur
652             Exception e = threads[i].getException();
653             if (e != null) {
654                 fail("An error occured in the get: " + e);
655             }
656             // we should have a 200 status
657             assertEquals(threads[i].getMethod().getStatusCode(), HttpStatus.SC_OK);
658         }
659     }
660 
661     public void testTimeout() {
662         MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
663         mgr.getParams().setDefaultMaxConnectionsPerHost(2);
664         
665         try{
666             HostConfiguration hostConfig = new HostConfiguration();
667             hostConfig.setHost("www.nosuchserver.com", 80, "http");
668             
669             HttpConnection conn1 = mgr.getConnection(hostConfig);
670             HttpConnection conn2 = mgr.getConnection(hostConfig);
671             
672             HttpConnection conn3 = mgr.getConnectionWithTimeout(hostConfig, 1000);
673             fail("Expected an HttpException.");
674             
675         }catch(ConnectTimeoutException e){
676             //Expected result
677         }
678     }
679     
680     static class FakeSecureProtocolSocketFactory implements SecureProtocolSocketFactory {
681         
682         public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
683             throws IOException, UnknownHostException {
684             throw new IllegalStateException("createSocket() should never have been called.");
685         }
686         
687         public Socket createSocket(String host, int port)
688             throws IOException, UnknownHostException {
689             throw new IllegalStateException("createSocket() should never have been called.");
690         }
691         
692         public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
693             throws IOException, UnknownHostException {
694             throw new IllegalStateException("createSocket() should never have been called.");
695         }
696         
697         public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort, 
698             HttpConnectionParams params)
699             throws IOException, UnknownHostException {
700             throw new IllegalStateException("createSocket() should never have been called.");
701         }
702     }
703     
704     static class GetConnectionThread extends Thread {
705         
706         private HostConfiguration hostConfiguration;
707         private MultiThreadedHttpConnectionManager connectionManager;
708         private HttpConnection connection;
709         private long timeout;
710         private Exception exception;
711         
712         public GetConnectionThread(
713             HostConfiguration hostConfiguration, 
714             MultiThreadedHttpConnectionManager connectionManager,
715             long timeout
716         ) {
717             this.hostConfiguration = hostConfiguration;
718             this.connectionManager = connectionManager; 
719             this.timeout = timeout;
720         }
721         
722         public void run() {
723             try {
724                 connection = connectionManager.getConnectionWithTimeout(hostConfiguration, timeout);
725             } catch (Exception e) {
726                 this.exception = e;
727             }            
728         }
729         
730         public Exception getException() {
731             return exception;
732         }
733         
734         public HttpConnection getConnection() {
735             return connection;
736         }
737 
738     }
739     
740 }
741