1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 package com.eviware.soapui.impl.wsdl.support.http;
43
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.io.OutputStream;
47 import java.lang.ref.Reference;
48 import java.lang.ref.ReferenceQueue;
49 import java.lang.ref.WeakReference;
50 import java.net.InetAddress;
51 import java.net.Socket;
52 import java.net.SocketException;
53 import java.util.ArrayList;
54 import java.util.HashMap;
55 import java.util.Iterator;
56 import java.util.LinkedList;
57 import java.util.Map;
58 import java.util.WeakHashMap;
59
60 import org.apache.commons.httpclient.ConnectionPoolTimeoutException;
61 import org.apache.commons.httpclient.HostConfiguration;
62 import org.apache.commons.httpclient.HttpConnection;
63 import org.apache.commons.httpclient.HttpConnectionManager;
64 import org.apache.commons.httpclient.HttpException;
65 import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
66 import org.apache.commons.httpclient.params.HttpConnectionParams;
67 import org.apache.commons.httpclient.protocol.Protocol;
68 import org.apache.commons.httpclient.util.IdleConnectionHandler;
69 import org.apache.log4j.Logger;
70
71 /***
72 * Manages a set of HttpConnections for various HostConfigurations. Modified to
73 * keep different pools for different keystores.
74 *
75 * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
76 * @author Eric Johnson
77 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
78 * @author Carl A. Dunham
79 *
80 * @since 2.0
81 */
82 public class SoapUIMultiThreadedHttpConnectionManager implements HttpConnectionManager
83 {
84
85
86
87 /*** Log object for this class. */
88 private static final Logger LOG = Logger.getLogger( SoapUIMultiThreadedHttpConnectionManager.class );
89
90 /*** The default maximum number of connections allowed per host */
91 public static final int DEFAULT_MAX_HOST_CONNECTIONS = 2;
92
93
94 /*** The default maximum number of connections allowed overall */
95 public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20;
96
97 /***
98 * A mapping from Reference to ConnectionSource. Used to reclaim resources
99 * when connections are lost to the garbage collector.
100 */
101 private static final Map REFERENCE_TO_CONNECTION_SOURCE = new HashMap();
102
103 /***
104 * The reference queue used to track when HttpConnections are lost to the
105 * garbage collector
106 */
107 private static final ReferenceQueue REFERENCE_QUEUE = new ReferenceQueue();
108
109 /***
110 * The thread responsible for handling lost connections.
111 */
112 private static ReferenceQueueThread REFERENCE_QUEUE_THREAD;
113
114 /***
115 * Holds references to all active instances of this class.
116 */
117 private static WeakHashMap ALL_CONNECTION_MANAGERS = new WeakHashMap();
118
119
120
121 /***
122 * Shuts down and cleans up resources used by all instances of
123 * MultiThreadedHttpConnectionManager. All static resources are released, all
124 * threads are stopped, and {@link #shutdown()} is called on all live
125 * instances of MultiThreadedHttpConnectionManager.
126 *
127 * @see #shutdown()
128 */
129 public static void shutdownAll()
130 {
131
132 synchronized( REFERENCE_TO_CONNECTION_SOURCE )
133 {
134
135 synchronized( ALL_CONNECTION_MANAGERS )
136 {
137
138
139 SoapUIMultiThreadedHttpConnectionManager[] connManagers = ( SoapUIMultiThreadedHttpConnectionManager[] )ALL_CONNECTION_MANAGERS
140 .keySet().toArray( new SoapUIMultiThreadedHttpConnectionManager[ALL_CONNECTION_MANAGERS.size()] );
141
142
143
144 for( int i = 0; i < connManagers.length; i++ )
145 {
146 if( connManagers[i] != null )
147 connManagers[i].shutdown();
148 }
149 }
150
151
152 if( REFERENCE_QUEUE_THREAD != null )
153 {
154 REFERENCE_QUEUE_THREAD.shutdown();
155 REFERENCE_QUEUE_THREAD = null;
156 }
157 REFERENCE_TO_CONNECTION_SOURCE.clear();
158 }
159 }
160
161 /***
162 * Stores the reference to the given connection along with the host config
163 * and connection pool. These values will be used to reclaim resources if the
164 * connection is lost to the garbage collector. This method should be called
165 * before a connection is released from the connection manager.
166 *
167 * <p>
168 * A static reference to the connection manager will also be stored. To
169 * ensure that the connection manager can be GCed
170 * {@link #removeReferenceToConnection(HttpConnection)} should be called for
171 * all connections that the connection manager is storing a reference to.
172 * </p>
173 *
174 * @param connection
175 * the connection to create a reference for
176 * @param hostConfiguration
177 * the connection's host config
178 * @param connectionPool
179 * the connection pool that created the connection
180 *
181 * @see #removeReferenceToConnection(HttpConnection)
182 */
183 private static void storeReferenceToConnection( HttpConnectionWithReference connection,
184 HostConfiguration hostConfiguration, ConnectionPool connectionPool )
185 {
186
187 ConnectionSource source = new ConnectionSource();
188 source.connectionPool = connectionPool;
189 source.hostConfiguration = hostConfiguration;
190
191 synchronized( REFERENCE_TO_CONNECTION_SOURCE )
192 {
193
194
195 if( REFERENCE_QUEUE_THREAD == null )
196 {
197 REFERENCE_QUEUE_THREAD = new ReferenceQueueThread();
198 REFERENCE_QUEUE_THREAD.start();
199 }
200
201 REFERENCE_TO_CONNECTION_SOURCE.put( connection.reference, source );
202 }
203 }
204
205 /***
206 * Closes and releases all connections currently checked out of the given
207 * connection pool.
208 *
209 * @param connectionPool
210 * the connection pool to shutdown the connections for
211 */
212 private static void shutdownCheckedOutConnections( ConnectionPool connectionPool )
213 {
214
215
216 ArrayList<HttpConnection> connectionsToClose = new ArrayList<HttpConnection>();
217
218 synchronized( REFERENCE_TO_CONNECTION_SOURCE )
219 {
220
221 Iterator referenceIter = REFERENCE_TO_CONNECTION_SOURCE.keySet().iterator();
222 while( referenceIter.hasNext() )
223 {
224 Reference ref = ( Reference )referenceIter.next();
225 ConnectionSource source = ( ConnectionSource )REFERENCE_TO_CONNECTION_SOURCE.get( ref );
226 if( source.connectionPool == connectionPool )
227 {
228 referenceIter.remove();
229 HttpConnection connection = ( HttpConnection )ref.get();
230 if( connection != null )
231 {
232 connectionsToClose.add( connection );
233 }
234 }
235 }
236 }
237
238
239
240 for( Iterator i = connectionsToClose.iterator(); i.hasNext(); )
241 {
242 HttpConnection connection = ( HttpConnection )i.next();
243 connection.close();
244
245
246 connection.setHttpConnectionManager( null );
247 connection.releaseConnection();
248 }
249 }
250
251 /***
252 * Removes the reference being stored for the given connection. This method
253 * should be called when the connection manager again has a direct reference
254 * to the connection.
255 *
256 * @param connection
257 * the connection to remove the reference for
258 *
259 * @see #storeReferenceToConnection(HttpConnection, HostConfiguration,
260 * ConnectionPool)
261 */
262 private static void removeReferenceToConnection( HttpConnectionWithReference connection )
263 {
264
265 synchronized( REFERENCE_TO_CONNECTION_SOURCE )
266 {
267 REFERENCE_TO_CONNECTION_SOURCE.remove( connection.reference );
268 }
269 }
270
271
272
273 /***
274 * Collection of parameters associated with this connection manager.
275 */
276 private HttpConnectionManagerParams params = new HttpConnectionManagerParams();
277
278 /*** Connection Pool */
279 private ConnectionPool connectionPool;
280
281 private volatile boolean shutdown = false;
282
283
284
285 /***
286 * No-args constructor
287 */
288 public SoapUIMultiThreadedHttpConnectionManager()
289 {
290 this.connectionPool = new ConnectionPool();
291 synchronized( ALL_CONNECTION_MANAGERS )
292 {
293 ALL_CONNECTION_MANAGERS.put( this, null );
294 }
295 }
296
297
298
299 /***
300 * Shuts down the connection manager and releases all resources. All
301 * connections associated with this class will be closed and released.
302 *
303 * <p>
304 * The connection manager can no longer be used once shut down.
305 *
306 * <p>
307 * Calling this method more than once will have no effect.
308 */
309 public synchronized void shutdown()
310 {
311 synchronized( connectionPool )
312 {
313 if( !shutdown )
314 {
315 shutdown = true;
316 connectionPool.shutdown();
317 }
318 }
319 }
320
321 /***
322 * Gets the staleCheckingEnabled value to be set on HttpConnections that are
323 * created.
324 *
325 * @return <code>true</code> if stale checking will be enabled on
326 * HttpConnections
327 *
328 * @see HttpConnection#isStaleCheckingEnabled()
329 *
330 * @deprecated Use
331 * {@link HttpConnectionManagerParams#isStaleCheckingEnabled()},
332 * {@link HttpConnectionManager#getParams()}.
333 */
334 public boolean isConnectionStaleCheckingEnabled()
335 {
336 return this.params.isStaleCheckingEnabled();
337 }
338
339 /***
340 * Sets the staleCheckingEnabled value to be set on HttpConnections that are
341 * created.
342 *
343 * @param connectionStaleCheckingEnabled
344 * <code>true</code> if stale checking will be enabled on
345 * HttpConnections
346 *
347 * @see HttpConnection#setStaleCheckingEnabled(boolean)
348 *
349 * @deprecated Use
350 * {@link HttpConnectionManagerParams#setStaleCheckingEnabled(boolean)}
351 * , {@link HttpConnectionManager#getParams()}.
352 */
353 public void setConnectionStaleCheckingEnabled( boolean connectionStaleCheckingEnabled )
354 {
355 this.params.setStaleCheckingEnabled( connectionStaleCheckingEnabled );
356 }
357
358 /***
359 * Sets the maximum number of connections allowed for a given
360 * HostConfiguration. Per RFC 2616 section 8.1.4, this value defaults to 2.
361 *
362 * @param maxHostConnections
363 * the number of connections allowed for each hostConfiguration
364 *
365 * @deprecated Use
366 * {@link HttpConnectionManagerParams#setDefaultMaxConnectionsPerHost(int)}
367 * , {@link HttpConnectionManager#getParams()}.
368 */
369 public void setMaxConnectionsPerHost( int maxHostConnections )
370 {
371 this.params.setDefaultMaxConnectionsPerHost( maxHostConnections );
372 }
373
374 /***
375 * Gets the maximum number of connections allowed for a given
376 * hostConfiguration.
377 *
378 * @return The maximum number of connections allowed for a given
379 * hostConfiguration.
380 *
381 * @deprecated Use
382 * {@link HttpConnectionManagerParams#getDefaultMaxConnectionsPerHost()}
383 * , {@link HttpConnectionManager#getParams()}.
384 */
385 public int getMaxConnectionsPerHost()
386 {
387 return this.params.getDefaultMaxConnectionsPerHost();
388 }
389
390 /***
391 * Sets the maximum number of connections allowed for this connection
392 * manager.
393 *
394 * @param maxTotalConnections
395 * the maximum number of connections allowed
396 *
397 * @deprecated Use
398 * {@link HttpConnectionManagerParams#setMaxTotalConnections(int)}
399 * , {@link HttpConnectionManager#getParams()}.
400 */
401 public void setMaxTotalConnections( int maxTotalConnections )
402 {
403 this.params.setMaxTotalConnections( maxTotalConnections );
404 }
405
406 /***
407 * Gets the maximum number of connections allowed for this connection
408 * manager.
409 *
410 * @return The maximum number of connections allowed
411 *
412 * @deprecated Use
413 * {@link HttpConnectionManagerParams#getMaxTotalConnections()},
414 * {@link HttpConnectionManager#getParams()}.
415 */
416 public int getMaxTotalConnections()
417 {
418 return this.params.getMaxTotalConnections();
419 }
420
421 /***
422 * @see HttpConnectionManager#getConnection(HostConfiguration)
423 */
424 public HttpConnection getConnection( HostConfiguration hostConfiguration )
425 {
426
427 while( true )
428 {
429 try
430 {
431 return getConnectionWithTimeout( hostConfiguration, 0 );
432 }
433 catch( ConnectionPoolTimeoutException e )
434 {
435
436
437
438
439
440 LOG.debug( "Unexpected exception while waiting for connection", e );
441 }
442 }
443 }
444
445 /***
446 * Gets a connection or waits if one is not available. A connection is
447 * available if one exists that is not being used or if fewer than
448 * maxHostConnections have been created in the connectionPool, and fewer than
449 * maxTotalConnections have been created in all connectionPools.
450 *
451 * @param hostConfiguration
452 * The host configuration specifying the connection details.
453 * @param timeout
454 * the number of milliseconds to wait for a connection, 0 to wait
455 * indefinitely
456 *
457 * @return HttpConnection an available connection
458 *
459 * @throws HttpException
460 * if a connection does not become available in 'timeout'
461 * milliseconds
462 *
463 * @since 3.0
464 */
465 public HttpConnection getConnectionWithTimeout( HostConfiguration hostConfiguration, long timeout )
466 throws ConnectionPoolTimeoutException
467 {
468
469 LOG.trace( "enter HttpConnectionManager.getConnectionWithTimeout(HostConfiguration, long)" );
470
471 if( hostConfiguration == null )
472 {
473 throw new IllegalArgumentException( "hostConfiguration is null" );
474 }
475
476 if( LOG.isDebugEnabled() )
477 {
478 LOG.debug( "HttpConnectionManager.getConnection: config = " + hostConfiguration + ", timeout = " + timeout );
479 }
480
481 final HttpConnection conn = doGetConnection( hostConfiguration, timeout );
482 conn.getParams().setParameter( SoapUIHostConfiguration.SOAPUI_SSL_CONFIG,
483 hostConfiguration.getParams().getParameter( SoapUIHostConfiguration.SOAPUI_SSL_CONFIG ) );
484
485
486
487 return new HttpConnectionAdapter( conn );
488 }
489
490 /***
491 * @see HttpConnectionManager#getConnection(HostConfiguration, long)
492 *
493 * @deprecated Use #getConnectionWithTimeout(HostConfiguration, long)
494 */
495 public HttpConnection getConnection( HostConfiguration hostConfiguration, long timeout ) throws HttpException
496 {
497
498 LOG.trace( "enter HttpConnectionManager.getConnection(HostConfiguration, long)" );
499 try
500 {
501 return getConnectionWithTimeout( hostConfiguration, timeout );
502 }
503 catch( ConnectionPoolTimeoutException e )
504 {
505 throw new HttpException( e.getMessage() );
506 }
507 }
508
509 private HttpConnection doGetConnection( HostConfiguration hostConfiguration, long timeout )
510 throws ConnectionPoolTimeoutException
511 {
512
513 HttpConnection connection = null;
514
515 int maxHostConnections = this.params.getMaxConnectionsPerHost( hostConfiguration );
516 int maxTotalConnections = this.params.getMaxTotalConnections();
517
518 synchronized( connectionPool )
519 {
520
521
522
523 hostConfiguration = new SoapUIHostConfiguration( hostConfiguration );
524 HostConnectionPool hostPool = connectionPool.getHostPool( hostConfiguration, true );
525 WaitingThread waitingThread = null;
526
527 boolean useTimeout = ( timeout > 0 );
528 long timeToWait = timeout;
529 long startWait = 0;
530 long endWait = 0;
531
532 while( connection == null )
533 {
534
535 if( shutdown )
536 {
537 throw new IllegalStateException( "Connection factory has been shutdown." );
538 }
539
540
541
542 if( hostPool.freeConnections.size() > 0 )
543 {
544 connection = connectionPool.getFreeConnection( hostConfiguration );
545
546
547
548 }
549 else if( ( hostPool.numConnections < maxHostConnections )
550 && ( connectionPool.numConnections < maxTotalConnections ) )
551 {
552
553 connection = connectionPool.createConnection( hostConfiguration );
554
555
556
557
558
559 }
560 else if( ( hostPool.numConnections < maxHostConnections ) && ( connectionPool.freeConnections.size() > 0 ) )
561 {
562
563 connectionPool.deleteLeastUsedConnection();
564 connection = connectionPool.createConnection( hostConfiguration );
565
566
567
568
569 }
570 else
571 {
572
573
574
575 try
576 {
577
578 if( useTimeout && timeToWait <= 0 )
579 {
580 throw new ConnectionPoolTimeoutException( "Timeout waiting for connection" );
581 }
582
583 if( LOG.isDebugEnabled() )
584 {
585 LOG.debug( "Unable to get a connection, waiting..., hostConfig=" + hostConfiguration );
586 }
587
588 if( waitingThread == null )
589 {
590 waitingThread = new WaitingThread();
591 waitingThread.hostConnectionPool = hostPool;
592 waitingThread.thread = Thread.currentThread();
593 }
594 else
595 {
596 waitingThread.interruptedByConnectionPool = false;
597 }
598
599 if( useTimeout )
600 {
601 startWait = System.currentTimeMillis();
602 }
603
604 hostPool.waitingThreads.addLast( waitingThread );
605 connectionPool.waitingThreads.addLast( waitingThread );
606 connectionPool.wait( timeToWait );
607 }
608 catch( InterruptedException e )
609 {
610 if( !waitingThread.interruptedByConnectionPool )
611 {
612 LOG.debug( "Interrupted while waiting for connection", e );
613 throw new IllegalThreadStateException(
614 "Interrupted while waiting in MultiThreadedHttpConnectionManager" );
615 }
616
617
618
619
620 }
621 finally
622 {
623 if( !waitingThread.interruptedByConnectionPool )
624 {
625
626
627
628
629 hostPool.waitingThreads.remove( waitingThread );
630 connectionPool.waitingThreads.remove( waitingThread );
631 }
632
633 if( useTimeout )
634 {
635 endWait = System.currentTimeMillis();
636 timeToWait -= ( endWait - startWait );
637 }
638 }
639 }
640 }
641 }
642 return connection;
643 }
644
645 /***
646 * Gets the total number of pooled connections for the given host
647 * configuration. This is the total number of connections that have been
648 * created and are still in use by this connection manager for the host
649 * configuration. This value will not exceed the
650 * {@link #getMaxConnectionsPerHost() maximum number of connections per host}
651 * .
652 *
653 * @param hostConfiguration
654 * The host configuration
655 * @return The total number of pooled connections
656 */
657 public int getConnectionsInPool( HostConfiguration hostConfiguration )
658 {
659 synchronized( connectionPool )
660 {
661 HostConnectionPool hostPool = connectionPool.getHostPool( hostConfiguration, false );
662 return ( hostPool != null ) ? hostPool.numConnections : 0;
663 }
664 }
665
666 /***
667 * Gets the total number of pooled connections. This is the total number of
668 * connections that have been created and are still in use by this connection
669 * manager. This value will not exceed the {@link #getMaxTotalConnections()
670 * maximum number of connections}.
671 *
672 * @return the total number of pooled connections
673 */
674 public int getConnectionsInPool()
675 {
676 synchronized( connectionPool )
677 {
678 return connectionPool.numConnections;
679 }
680 }
681
682 /***
683 * Gets the number of connections in use for this configuration.
684 *
685 * @param hostConfiguration
686 * the key that connections are tracked on
687 * @return the number of connections in use
688 *
689 * @deprecated Use {@link #getConnectionsInPool(HostConfiguration)}
690 */
691 public int getConnectionsInUse( HostConfiguration hostConfiguration )
692 {
693 return getConnectionsInPool( hostConfiguration );
694 }
695
696 /***
697 * Gets the total number of connections in use.
698 *
699 * @return the total number of connections in use
700 *
701 * @deprecated Use {@link #getConnectionsInPool()}
702 */
703 public int getConnectionsInUse()
704 {
705 return getConnectionsInPool();
706 }
707
708 /***
709 * Deletes all closed connections. Only connections currently owned by the
710 * connection manager are processed.
711 *
712 * @see HttpConnection#isOpen()
713 *
714 * @since 3.0
715 */
716 public void deleteClosedConnections()
717 {
718 connectionPool.deleteClosedConnections();
719 }
720
721 /***
722 * @since 3.0
723 */
724 public void closeIdleConnections( long idleTimeout )
725 {
726 connectionPool.closeIdleConnections( idleTimeout );
727 deleteClosedConnections();
728 }
729
730 /***
731 * Make the given HttpConnection available for use by other requests. If
732 * another thread is blocked in getConnection() that could use this
733 * connection, it will be woken up.
734 *
735 * @param conn
736 * the HttpConnection to make available.
737 */
738 public void releaseConnection( HttpConnection conn )
739 {
740 LOG.trace( "enter HttpConnectionManager.releaseConnection(HttpConnection)" );
741
742 if( conn instanceof HttpConnectionAdapter )
743 {
744
745 conn = ( ( HttpConnectionAdapter )conn ).getWrappedConnection();
746 }
747 else
748 {
749
750
751 }
752
753
754 finishLastResponse( conn );
755
756 connectionPool.freeConnection( conn );
757 }
758
759 private void finishLastResponse( HttpConnection conn )
760 {
761 InputStream lastResponse = conn.getLastResponseInputStream();
762 if( lastResponse != null )
763 {
764 conn.setLastResponseInputStream( null );
765 try
766 {
767 lastResponse.close();
768 }
769 catch( IOException ioe )
770 {
771 conn.close();
772 }
773 }
774 }
775
776 /***
777 * Gets the host configuration for a connection.
778 *
779 * @param conn
780 * the connection to get the configuration of
781 * @return a new HostConfiguration
782 */
783 private HostConfiguration configurationForConnection( HttpConnection conn )
784 {
785
786 HostConfiguration connectionConfiguration = new SoapUIHostConfiguration();
787
788 connectionConfiguration.setHost( conn.getHost(), conn.getPort(), conn.getProtocol() );
789 if( conn.getLocalAddress() != null )
790 {
791 connectionConfiguration.setLocalAddress( conn.getLocalAddress() );
792 }
793 if( conn.getProxyHost() != null )
794 {
795 connectionConfiguration.setProxy( conn.getProxyHost(), conn.getProxyPort() );
796 }
797
798 if( conn.getParams().getParameter( SoapUIHostConfiguration.SOAPUI_SSL_CONFIG ) != null )
799 connectionConfiguration.getParams().setParameter( SoapUIHostConfiguration.SOAPUI_SSL_CONFIG,
800 conn.getParams().getParameter( SoapUIHostConfiguration.SOAPUI_SSL_CONFIG ) );
801
802 return connectionConfiguration;
803 }
804
805 /***
806 * Returns {@link HttpConnectionManagerParams parameters} associated with
807 * this connection manager.
808 *
809 * @since 3.0
810 *
811 * @see HttpConnectionManagerParams
812 */
813 public HttpConnectionManagerParams getParams()
814 {
815 return this.params;
816 }
817
818 /***
819 * Assigns {@link HttpConnectionManagerParams parameters} for this connection
820 * manager.
821 *
822 * @since 3.0
823 *
824 * @see HttpConnectionManagerParams
825 */
826 public void setParams( final HttpConnectionManagerParams params )
827 {
828 if( params == null )
829 {
830 throw new IllegalArgumentException( "Parameters may not be null" );
831 }
832 this.params = params;
833 }
834
835 /***
836 * Global Connection Pool, including per-host pools
837 */
838 private class ConnectionPool
839 {
840
841 /*** The list of free connections */
842 private LinkedList freeConnections = new LinkedList();
843
844 /*** The list of WaitingThreads waiting for a connection */
845 private LinkedList waitingThreads = new LinkedList();
846
847 /***
848 * Map where keys are {@link HostConfiguration}s and values are
849 * {@link HostConnectionPool}s
850 */
851 private final Map mapHosts = new HashMap();
852
853 private IdleConnectionHandler idleConnectionHandler = new IdleConnectionHandler();
854
855 /*** The number of created connections */
856 private int numConnections = 0;
857
858 /***
859 * Cleans up all connection pool resources.
860 */
861 public synchronized void shutdown()
862 {
863
864 Iterator<?> iter = freeConnections.iterator();
865 while( iter.hasNext() )
866 {
867 HttpConnection conn = ( HttpConnection )iter.next();
868 iter.remove();
869 conn.close();
870 }
871
872
873 shutdownCheckedOutConnections( this );
874
875
876 iter = waitingThreads.iterator();
877 while( iter.hasNext() )
878 {
879 WaitingThread waiter = ( WaitingThread )iter.next();
880 iter.remove();
881 waiter.interruptedByConnectionPool = true;
882 waiter.thread.interrupt();
883 }
884
885
886 mapHosts.clear();
887
888
889 idleConnectionHandler.removeAll();
890 }
891
892 /***
893 * Creates a new connection and returns it for use of the calling method.
894 *
895 * @param hostConfiguration
896 * the configuration for the connection
897 * @return a new connection or <code>null</code> if none are available
898 */
899 public synchronized HttpConnection createConnection( HostConfiguration hostConfiguration )
900 {
901 HostConnectionPool hostPool = getHostPool( hostConfiguration, true );
902 if( LOG.isDebugEnabled() )
903 {
904 LOG.debug( "Allocating new connection, hostConfig=" + hostConfiguration );
905 }
906 HttpConnectionWithReference connection = new HttpConnectionWithReference( hostConfiguration );
907 connection.getParams().setDefaults( SoapUIMultiThreadedHttpConnectionManager.this.params );
908 connection.setHttpConnectionManager( SoapUIMultiThreadedHttpConnectionManager.this );
909 numConnections++ ;
910 hostPool.numConnections++ ;
911
912
913
914 storeReferenceToConnection( connection, hostConfiguration, this );
915 return connection;
916 }
917
918 /***
919 * Handles cleaning up for a lost connection with the given config.
920 * Decrements any connection counts and notifies waiting threads, if
921 * appropriate.
922 *
923 * @param config
924 * the host configuration of the connection that was lost
925 */
926 public synchronized void handleLostConnection( HostConfiguration config )
927 {
928 HostConnectionPool hostPool = getHostPool( config, true );
929 hostPool.numConnections-- ;
930 if( ( hostPool.numConnections == 0 ) && hostPool.waitingThreads.isEmpty() )
931 {
932
933 mapHosts.remove( config );
934 }
935
936 numConnections-- ;
937 notifyWaitingThread( config );
938 }
939
940 /***
941 * Get the pool (list) of connections available for the given hostConfig.
942 *
943 * @param hostConfiguration
944 * the configuraton for the connection pool
945 * @param create
946 * <code>true</code> to create a pool if not found,
947 * <code>false</code> to return <code>null</code>
948 *
949 * @return a pool (list) of connections available for the given config, or
950 * <code>null</code> if neither found nor created
951 */
952 public synchronized HostConnectionPool getHostPool( HostConfiguration hostConfiguration, boolean create )
953 {
954 LOG.trace( "enter HttpConnectionManager.ConnectionPool.getHostPool(HostConfiguration)" );
955
956
957 HostConnectionPool listConnections = ( HostConnectionPool )mapHosts.get( hostConfiguration );
958 if( ( listConnections == null ) && create )
959 {
960
961 listConnections = new HostConnectionPool();
962 listConnections.hostConfiguration = hostConfiguration;
963 mapHosts.put( hostConfiguration, listConnections );
964 }
965
966 return listConnections;
967 }
968
969 /***
970 * If available, get a free connection for this host
971 *
972 * @param hostConfiguration
973 * the configuraton for the connection pool
974 * @return an available connection for the given config
975 */
976 public synchronized HttpConnection getFreeConnection( HostConfiguration hostConfiguration )
977 {
978
979 HttpConnectionWithReference connection = null;
980
981 HostConnectionPool hostPool = getHostPool( hostConfiguration, false );
982
983 if( ( hostPool != null ) && ( hostPool.freeConnections.size() > 0 ) )
984 {
985 connection = ( HttpConnectionWithReference )hostPool.freeConnections.removeLast();
986 freeConnections.remove( connection );
987
988
989 storeReferenceToConnection( connection, hostConfiguration, this );
990 if( LOG.isDebugEnabled() )
991 {
992 LOG.debug( "Getting free connection, hostConfig=" + hostConfiguration );
993 }
994
995
996 idleConnectionHandler.remove( connection );
997 }
998 else if( LOG.isDebugEnabled() )
999 {
1000 LOG.debug( "There were no free connections to get, hostConfig=" + hostConfiguration );
1001 }
1002 return connection;
1003 }
1004
1005 /***
1006 * Deletes all closed connections.
1007 */
1008 public synchronized void deleteClosedConnections()
1009 {
1010
1011 Iterator iter = freeConnections.iterator();
1012
1013 while( iter.hasNext() )
1014 {
1015 HttpConnection conn = ( HttpConnection )iter.next();
1016 if( !conn.isOpen() )
1017 {
1018 iter.remove();
1019 deleteConnection( conn );
1020 }
1021 }
1022 }
1023
1024 /***
1025 * Closes idle connections.
1026 *
1027 * @param idleTimeout
1028 */
1029 public synchronized void closeIdleConnections( long idleTimeout )
1030 {
1031 idleConnectionHandler.closeIdleConnections( idleTimeout );
1032 }
1033
1034 /***
1035 * Deletes the given connection. This will remove all reference to the
1036 * connection so that it can be GCed.
1037 *
1038 * <p>
1039 * <b>Note:</b> Does not remove the connection from the freeConnections
1040 * list. It is assumed that the caller has already handled this case.
1041 * </p>
1042 *
1043 * @param connection
1044 * The connection to delete
1045 */
1046 private synchronized void deleteConnection( HttpConnection connection )
1047 {
1048
1049 HostConfiguration connectionConfiguration = configurationForConnection( connection );
1050
1051 if( LOG.isDebugEnabled() )
1052 {
1053 LOG.debug( "Reclaiming connection, hostConfig=" + connectionConfiguration );
1054 }
1055
1056 connection.close();
1057
1058 HostConnectionPool hostPool = getHostPool( connectionConfiguration, true );
1059
1060 hostPool.freeConnections.remove( connection );
1061 hostPool.numConnections-- ;
1062 numConnections-- ;
1063 if( ( hostPool.numConnections == 0 ) && hostPool.waitingThreads.isEmpty() )
1064 {
1065
1066 mapHosts.remove( connectionConfiguration );
1067 }
1068
1069
1070 idleConnectionHandler.remove( connection );
1071 }
1072
1073 /***
1074 * Close and delete an old, unused connection to make room for a new one.
1075 */
1076 public synchronized void deleteLeastUsedConnection()
1077 {
1078
1079 HttpConnection connection = ( HttpConnection )freeConnections.removeFirst();
1080
1081 if( connection != null )
1082 {
1083 deleteConnection( connection );
1084 }
1085 else if( LOG.isDebugEnabled() )
1086 {
1087 LOG.debug( "Attempted to reclaim an unused connection but there were none." );
1088 }
1089 }
1090
1091 /***
1092 * Notifies a waiting thread that a connection for the given configuration
1093 * is available.
1094 *
1095 * @param configuration
1096 * the host config to use for notifying
1097 * @see #notifyWaitingThread(HostConnectionPool)
1098 */
1099 public synchronized void notifyWaitingThread( HostConfiguration configuration )
1100 {
1101 notifyWaitingThread( getHostPool( configuration, true ) );
1102 }
1103
1104 /***
1105 * Notifies a waiting thread that a connection for the given configuration
1106 * is available. This will wake a thread waiting in this host pool or if
1107 * there is not one a thread in the connection pool will be notified.
1108 *
1109 * @param hostPool
1110 * the host pool to use for notifying
1111 */
1112 public synchronized void notifyWaitingThread( HostConnectionPool hostPool )
1113 {
1114
1115
1116
1117
1118 WaitingThread waitingThread = null;
1119
1120 if( hostPool.waitingThreads.size() > 0 )
1121 {
1122 if( LOG.isDebugEnabled() )
1123 {
1124 LOG.debug( "Notifying thread waiting on host pool, hostConfig=" + hostPool.hostConfiguration );
1125 }
1126 waitingThread = ( WaitingThread )hostPool.waitingThreads.removeFirst();
1127 waitingThreads.remove( waitingThread );
1128 }
1129 else if( waitingThreads.size() > 0 )
1130 {
1131 if( LOG.isDebugEnabled() )
1132 {
1133 LOG.debug( "No-one waiting on host pool, notifying next waiting thread." );
1134 }
1135 waitingThread = ( WaitingThread )waitingThreads.removeFirst();
1136 waitingThread.hostConnectionPool.waitingThreads.remove( waitingThread );
1137 }
1138 else if( LOG.isDebugEnabled() )
1139 {
1140 LOG.debug( "Notifying no-one, there are no waiting threads" );
1141 }
1142
1143 if( waitingThread != null )
1144 {
1145 waitingThread.interruptedByConnectionPool = true;
1146 waitingThread.thread.interrupt();
1147 }
1148 }
1149
1150 /***
1151 * Marks the given connection as free.
1152 *
1153 * @param conn
1154 * a connection that is no longer being used
1155 */
1156 public void freeConnection( HttpConnection conn )
1157 {
1158
1159 HostConfiguration connectionConfiguration = configurationForConnection( conn );
1160
1161 if( LOG.isDebugEnabled() )
1162 {
1163 LOG.debug( "Freeing connection, hostConfig=" + connectionConfiguration );
1164 }
1165
1166 synchronized( this )
1167 {
1168
1169 if( shutdown )
1170 {
1171
1172
1173
1174 conn.close();
1175 return;
1176 }
1177
1178 HostConnectionPool hostPool = getHostPool( connectionConfiguration, true );
1179
1180
1181 hostPool.freeConnections.add( conn );
1182 if( hostPool.numConnections == 0 )
1183 {
1184
1185 LOG.error( "Host connection pool not found, hostConfig=" + connectionConfiguration );
1186 hostPool.numConnections = 1;
1187 }
1188
1189 freeConnections.add( conn );
1190
1191
1192
1193
1194 removeReferenceToConnection( ( HttpConnectionWithReference )conn );
1195 if( numConnections == 0 )
1196 {
1197
1198 LOG.error( "Host connection pool not found, hostConfig=" + connectionConfiguration );
1199 numConnections = 1;
1200 }
1201
1202
1203 idleConnectionHandler.add( conn );
1204
1205 notifyWaitingThread( hostPool );
1206 }
1207 }
1208 }
1209
1210 /***
1211 * A simple struct-like class to combine the objects needed to release a
1212 * connection's resources when claimed by the garbage collector.
1213 */
1214 private static class ConnectionSource
1215 {
1216
1217 /*** The connection pool that created the connection */
1218 public ConnectionPool connectionPool;
1219
1220 /*** The connection's host configuration */
1221 public HostConfiguration hostConfiguration;
1222 }
1223
1224 /***
1225 * A simple struct-like class to combine the connection list and the count of
1226 * created connections.
1227 */
1228 private static class HostConnectionPool
1229 {
1230 /*** The hostConfig this pool is for */
1231 public HostConfiguration hostConfiguration;
1232
1233 /*** The list of free connections */
1234 public LinkedList freeConnections = new LinkedList();
1235
1236 /*** The list of WaitingThreads for this host */
1237 public LinkedList waitingThreads = new LinkedList();
1238
1239 /*** The number of created connections */
1240 public int numConnections = 0;
1241 }
1242
1243 /***
1244 * A simple struct-like class to combine the waiting thread and the
1245 * connection pool it is waiting on.
1246 */
1247 private static class WaitingThread
1248 {
1249 /*** The thread that is waiting for a connection */
1250 public Thread thread;
1251
1252 /*** The connection pool the thread is waiting for */
1253 public HostConnectionPool hostConnectionPool;
1254
1255 /***
1256 * Flag to indicate if the thread was interrupted by the ConnectionPool.
1257 * Set to true inside
1258 * {@link ConnectionPool#notifyWaitingThread(HostConnectionPool)} before
1259 * the thread is interrupted.
1260 */
1261 public boolean interruptedByConnectionPool = false;
1262 }
1263
1264 /***
1265 * A thread for listening for HttpConnections reclaimed by the garbage
1266 * collector.
1267 */
1268 private static class ReferenceQueueThread extends Thread
1269 {
1270
1271 private volatile boolean shutdown = false;
1272
1273 /***
1274 * Create an instance and make this a daemon thread.
1275 */
1276 public ReferenceQueueThread()
1277 {
1278 setDaemon( true );
1279 setName( "MultiThreadedHttpConnectionManager cleanup" );
1280 }
1281
1282 public void shutdown()
1283 {
1284 this.shutdown = true;
1285 this.interrupt();
1286 }
1287
1288 /***
1289 * Handles cleaning up for the given connection reference.
1290 *
1291 * @param ref
1292 * the reference to clean up
1293 */
1294 private void handleReference( Reference ref )
1295 {
1296
1297 ConnectionSource source = null;
1298
1299 synchronized( REFERENCE_TO_CONNECTION_SOURCE )
1300 {
1301 source = ( ConnectionSource )REFERENCE_TO_CONNECTION_SOURCE.remove( ref );
1302 }
1303
1304
1305 if( source != null )
1306 {
1307 if( LOG.isDebugEnabled() )
1308 {
1309 LOG.debug( "Connection reclaimed by garbage collector, hostConfig=" + source.hostConfiguration );
1310 }
1311
1312 source.connectionPool.handleLostConnection( source.hostConfiguration );
1313 }
1314 }
1315
1316 /***
1317 * Start execution.
1318 */
1319 public void run()
1320 {
1321 while( !shutdown )
1322 {
1323 try
1324 {
1325
1326 Reference ref = REFERENCE_QUEUE.remove();
1327 if( ref != null )
1328 {
1329 handleReference( ref );
1330 }
1331 }
1332 catch( InterruptedException e )
1333 {
1334 LOG.debug( "ReferenceQueueThread interrupted", e );
1335 }
1336 }
1337 }
1338
1339 }
1340
1341 /***
1342 * A connection that keeps a reference to itself.
1343 */
1344 public static class HttpConnectionWithReference extends HttpConnection implements ConnectionWithSocket
1345 {
1346
1347 public WeakReference reference = new WeakReference( this, REFERENCE_QUEUE );
1348
1349 /***
1350 * @param hostConfiguration
1351 */
1352 public HttpConnectionWithReference( HostConfiguration hostConfiguration )
1353 {
1354 super( hostConfiguration );
1355 }
1356
1357 public Socket getConnectionSocket()
1358 {
1359 return getSocket();
1360 }
1361
1362 }
1363
1364 /***
1365 * An HttpConnection wrapper that ensures a connection cannot be used once
1366 * released.
1367 */
1368 public static class HttpConnectionAdapter extends HttpConnection implements ConnectionWithSocket
1369 {
1370
1371
1372 private HttpConnection wrappedConnection;
1373
1374 /***
1375 * Creates a new HttpConnectionAdapter.
1376 *
1377 * @param connection
1378 * the connection to be wrapped
1379 */
1380 public HttpConnectionAdapter( HttpConnection connection )
1381 {
1382 super( connection.getHost(), connection.getPort(), connection.getProtocol() );
1383 this.wrappedConnection = connection;
1384 }
1385
1386 /***
1387 * Tests if the wrapped connection is still available.
1388 *
1389 * @return boolean
1390 */
1391 protected boolean hasConnection()
1392 {
1393 return wrappedConnection != null;
1394 }
1395
1396 /***
1397 * @return HttpConnection
1398 */
1399 HttpConnection getWrappedConnection()
1400 {
1401 return wrappedConnection;
1402 }
1403
1404 public void close()
1405 {
1406 if( hasConnection() )
1407 {
1408 wrappedConnection.close();
1409 }
1410 else
1411 {
1412
1413 }
1414 }
1415
1416 public InetAddress getLocalAddress()
1417 {
1418 if( hasConnection() )
1419 {
1420 return wrappedConnection.getLocalAddress();
1421 }
1422 else
1423 {
1424 return null;
1425 }
1426 }
1427
1428 /***
1429 * @deprecated
1430 */
1431 public boolean isStaleCheckingEnabled()
1432 {
1433 if( hasConnection() )
1434 {
1435 return wrappedConnection.isStaleCheckingEnabled();
1436 }
1437 else
1438 {
1439 return false;
1440 }
1441 }
1442
1443 public void setLocalAddress( InetAddress localAddress )
1444 {
1445 if( hasConnection() )
1446 {
1447 wrappedConnection.setLocalAddress( localAddress );
1448 }
1449 else
1450 {
1451 throw new IllegalStateException( "Connection has been released" );
1452 }
1453 }
1454
1455 /***
1456 * @deprecated
1457 */
1458 public void setStaleCheckingEnabled( boolean staleCheckEnabled )
1459 {
1460 if( hasConnection() )
1461 {
1462 wrappedConnection.setStaleCheckingEnabled( staleCheckEnabled );
1463 }
1464 else
1465 {
1466 throw new IllegalStateException( "Connection has been released" );
1467 }
1468 }
1469
1470 public String getHost()
1471 {
1472 if( hasConnection() )
1473 {
1474 return wrappedConnection.getHost();
1475 }
1476 else
1477 {
1478 return null;
1479 }
1480 }
1481
1482 public HttpConnectionManager getHttpConnectionManager()
1483 {
1484 if( hasConnection() )
1485 {
1486 return wrappedConnection.getHttpConnectionManager();
1487 }
1488 else
1489 {
1490 return null;
1491 }
1492 }
1493
1494 public InputStream getLastResponseInputStream()
1495 {
1496 if( hasConnection() )
1497 {
1498 return wrappedConnection.getLastResponseInputStream();
1499 }
1500 else
1501 {
1502 return null;
1503 }
1504 }
1505
1506 public int getPort()
1507 {
1508 if( hasConnection() )
1509 {
1510 return wrappedConnection.getPort();
1511 }
1512 else
1513 {
1514 return -1;
1515 }
1516 }
1517
1518 public Protocol getProtocol()
1519 {
1520 if( hasConnection() )
1521 {
1522 return wrappedConnection.getProtocol();
1523 }
1524 else
1525 {
1526 return null;
1527 }
1528 }
1529
1530 public String getProxyHost()
1531 {
1532 if( hasConnection() )
1533 {
1534 return wrappedConnection.getProxyHost();
1535 }
1536 else
1537 {
1538 return null;
1539 }
1540 }
1541
1542 public int getProxyPort()
1543 {
1544 if( hasConnection() )
1545 {
1546 return wrappedConnection.getProxyPort();
1547 }
1548 else
1549 {
1550 return -1;
1551 }
1552 }
1553
1554 public OutputStream getRequestOutputStream() throws IOException, IllegalStateException
1555 {
1556 if( hasConnection() )
1557 {
1558 return wrappedConnection.getRequestOutputStream();
1559 }
1560 else
1561 {
1562 return null;
1563 }
1564 }
1565
1566 public InputStream getResponseInputStream() throws IOException, IllegalStateException
1567 {
1568 if( hasConnection() )
1569 {
1570 return wrappedConnection.getResponseInputStream();
1571 }
1572 else
1573 {
1574 return null;
1575 }
1576 }
1577
1578 public boolean isOpen()
1579 {
1580 if( hasConnection() )
1581 {
1582 return wrappedConnection.isOpen();
1583 }
1584 else
1585 {
1586 return false;
1587 }
1588 }
1589
1590 public boolean closeIfStale() throws IOException
1591 {
1592 if( hasConnection() )
1593 {
1594 return wrappedConnection.closeIfStale();
1595 }
1596 else
1597 {
1598 return false;
1599 }
1600 }
1601
1602 public boolean isProxied()
1603 {
1604 if( hasConnection() )
1605 {
1606 return wrappedConnection.isProxied();
1607 }
1608 else
1609 {
1610 return false;
1611 }
1612 }
1613
1614 public boolean isResponseAvailable() throws IOException
1615 {
1616 if( hasConnection() )
1617 {
1618 return wrappedConnection.isResponseAvailable();
1619 }
1620 else
1621 {
1622 return false;
1623 }
1624 }
1625
1626 public boolean isResponseAvailable( int timeout ) throws IOException
1627 {
1628 if( hasConnection() )
1629 {
1630 return wrappedConnection.isResponseAvailable( timeout );
1631 }
1632 else
1633 {
1634 return false;
1635 }
1636 }
1637
1638 public boolean isSecure()
1639 {
1640 if( hasConnection() )
1641 {
1642 return wrappedConnection.isSecure();
1643 }
1644 else
1645 {
1646 return false;
1647 }
1648 }
1649
1650 public boolean isTransparent()
1651 {
1652 if( hasConnection() )
1653 {
1654 return wrappedConnection.isTransparent();
1655 }
1656 else
1657 {
1658 return false;
1659 }
1660 }
1661
1662 public void open() throws IOException
1663 {
1664 if( hasConnection() )
1665 {
1666 wrappedConnection.open();
1667 }
1668 else
1669 {
1670 throw new IllegalStateException( "Connection has been released" );
1671 }
1672 }
1673
1674 /***
1675 * @deprecated
1676 */
1677 public void print( String data ) throws IOException, IllegalStateException
1678 {
1679 if( hasConnection() )
1680 {
1681 wrappedConnection.print( data );
1682 }
1683 else
1684 {
1685 throw new IllegalStateException( "Connection has been released" );
1686 }
1687 }
1688
1689 public void printLine() throws IOException, IllegalStateException
1690 {
1691 if( hasConnection() )
1692 {
1693 wrappedConnection.printLine();
1694 }
1695 else
1696 {
1697 throw new IllegalStateException( "Connection has been released" );
1698 }
1699 }
1700
1701 /***
1702 * @deprecated
1703 */
1704 public void printLine( String data ) throws IOException, IllegalStateException
1705 {
1706 if( hasConnection() )
1707 {
1708 wrappedConnection.printLine( data );
1709 }
1710 else
1711 {
1712 throw new IllegalStateException( "Connection has been released" );
1713 }
1714 }
1715
1716 /***
1717 * @deprecated
1718 */
1719 public String readLine() throws IOException, IllegalStateException
1720 {
1721 if( hasConnection() )
1722 {
1723 return wrappedConnection.readLine();
1724 }
1725 else
1726 {
1727 throw new IllegalStateException( "Connection has been released" );
1728 }
1729 }
1730
1731 public String readLine( String charset ) throws IOException, IllegalStateException
1732 {
1733 if( hasConnection() )
1734 {
1735 return wrappedConnection.readLine( charset );
1736 }
1737 else
1738 {
1739 throw new IllegalStateException( "Connection has been released" );
1740 }
1741 }
1742
1743 public void releaseConnection()
1744 {
1745 if( !isLocked() && hasConnection() )
1746 {
1747 HttpConnection wrappedConnection = this.wrappedConnection;
1748 this.wrappedConnection = null;
1749 wrappedConnection.releaseConnection();
1750 }
1751 else
1752 {
1753
1754 }
1755 }
1756
1757 /***
1758 * @deprecated
1759 */
1760 public void setConnectionTimeout( int timeout )
1761 {
1762 if( hasConnection() )
1763 {
1764 wrappedConnection.setConnectionTimeout( timeout );
1765 }
1766 else
1767 {
1768
1769 }
1770 }
1771
1772 public void setHost( String host ) throws IllegalStateException
1773 {
1774 if( hasConnection() )
1775 {
1776 wrappedConnection.setHost( host );
1777 }
1778 else
1779 {
1780
1781 }
1782 }
1783
1784 public void setHttpConnectionManager( HttpConnectionManager httpConnectionManager )
1785 {
1786 if( hasConnection() )
1787 {
1788 wrappedConnection.setHttpConnectionManager( httpConnectionManager );
1789 }
1790 else
1791 {
1792
1793 }
1794 }
1795
1796 public void setLastResponseInputStream( InputStream inStream )
1797 {
1798 if( hasConnection() )
1799 {
1800 wrappedConnection.setLastResponseInputStream( inStream );
1801 }
1802 else
1803 {
1804
1805 }
1806 }
1807
1808 public void setPort( int port ) throws IllegalStateException
1809 {
1810 if( hasConnection() )
1811 {
1812 wrappedConnection.setPort( port );
1813 }
1814 else
1815 {
1816
1817 }
1818 }
1819
1820 public void setProtocol( Protocol protocol )
1821 {
1822 if( hasConnection() )
1823 {
1824 wrappedConnection.setProtocol( protocol );
1825 }
1826 else
1827 {
1828
1829 }
1830 }
1831
1832 public void setProxyHost( String host ) throws IllegalStateException
1833 {
1834 if( hasConnection() )
1835 {
1836 wrappedConnection.setProxyHost( host );
1837 }
1838 else
1839 {
1840
1841 }
1842 }
1843
1844 public void setProxyPort( int port ) throws IllegalStateException
1845 {
1846 if( hasConnection() )
1847 {
1848 wrappedConnection.setProxyPort( port );
1849 }
1850 else
1851 {
1852
1853 }
1854 }
1855
1856 /***
1857 * @deprecated
1858 */
1859 public void setSoTimeout( int timeout ) throws SocketException, IllegalStateException
1860 {
1861 if( hasConnection() )
1862 {
1863 wrappedConnection.setSoTimeout( timeout );
1864 }
1865 else
1866 {
1867
1868 }
1869 }
1870
1871 /***
1872 * @deprecated
1873 */
1874 public void shutdownOutput()
1875 {
1876 if( hasConnection() )
1877 {
1878 wrappedConnection.shutdownOutput();
1879 }
1880 else
1881 {
1882
1883 }
1884 }
1885
1886 public void tunnelCreated() throws IllegalStateException, IOException
1887 {
1888 if( hasConnection() )
1889 {
1890 wrappedConnection.tunnelCreated();
1891 }
1892 else
1893 {
1894
1895 }
1896 }
1897
1898 public void write( byte[] data, int offset, int length ) throws IOException, IllegalStateException
1899 {
1900 if( hasConnection() )
1901 {
1902 wrappedConnection.write( data, offset, length );
1903 }
1904 else
1905 {
1906 throw new IllegalStateException( "Connection has been released" );
1907 }
1908 }
1909
1910 public void write( byte[] data ) throws IOException, IllegalStateException
1911 {
1912 if( hasConnection() )
1913 {
1914 wrappedConnection.write( data );
1915 }
1916 else
1917 {
1918 throw new IllegalStateException( "Connection has been released" );
1919 }
1920 }
1921
1922 public void writeLine() throws IOException, IllegalStateException
1923 {
1924 if( hasConnection() )
1925 {
1926 wrappedConnection.writeLine();
1927 }
1928 else
1929 {
1930 throw new IllegalStateException( "Connection has been released" );
1931 }
1932 }
1933
1934 public void writeLine( byte[] data ) throws IOException, IllegalStateException
1935 {
1936 if( hasConnection() )
1937 {
1938 wrappedConnection.writeLine( data );
1939 }
1940 else
1941 {
1942 throw new IllegalStateException( "Connection has been released" );
1943 }
1944 }
1945
1946 public void flushRequestOutputStream() throws IOException
1947 {
1948 if( hasConnection() )
1949 {
1950 wrappedConnection.flushRequestOutputStream();
1951 }
1952 else
1953 {
1954 throw new IllegalStateException( "Connection has been released" );
1955 }
1956 }
1957
1958 /***
1959 * @deprecated
1960 */
1961 public int getSoTimeout() throws SocketException
1962 {
1963 if( hasConnection() )
1964 {
1965 return wrappedConnection.getSoTimeout();
1966 }
1967 else
1968 {
1969 throw new IllegalStateException( "Connection has been released" );
1970 }
1971 }
1972
1973 /***
1974 * @deprecated
1975 */
1976 public String getVirtualHost()
1977 {
1978 if( hasConnection() )
1979 {
1980 return wrappedConnection.getVirtualHost();
1981 }
1982 else
1983 {
1984 throw new IllegalStateException( "Connection has been released" );
1985 }
1986 }
1987
1988 /***
1989 * @deprecated
1990 */
1991 public void setVirtualHost( String host ) throws IllegalStateException
1992 {
1993 if( hasConnection() )
1994 {
1995 wrappedConnection.setVirtualHost( host );
1996 }
1997 else
1998 {
1999 throw new IllegalStateException( "Connection has been released" );
2000 }
2001 }
2002
2003 public int getSendBufferSize() throws SocketException
2004 {
2005 if( hasConnection() )
2006 {
2007 return wrappedConnection.getSendBufferSize();
2008 }
2009 else
2010 {
2011 throw new IllegalStateException( "Connection has been released" );
2012 }
2013 }
2014
2015 /***
2016 * @deprecated
2017 */
2018 public void setSendBufferSize( int sendBufferSize ) throws SocketException
2019 {
2020 if( hasConnection() )
2021 {
2022 wrappedConnection.setSendBufferSize( sendBufferSize );
2023 }
2024 else
2025 {
2026 throw new IllegalStateException( "Connection has been released" );
2027 }
2028 }
2029
2030 public HttpConnectionParams getParams()
2031 {
2032 if( hasConnection() )
2033 {
2034 return wrappedConnection.getParams();
2035 }
2036 else
2037 {
2038 throw new IllegalStateException( "Connection has been released" );
2039 }
2040 }
2041
2042 public void setParams( final HttpConnectionParams params )
2043 {
2044 if( hasConnection() )
2045 {
2046 wrappedConnection.setParams( params );
2047 }
2048 else
2049 {
2050 throw new IllegalStateException( "Connection has been released" );
2051 }
2052 }
2053
2054
2055
2056
2057
2058
2059
2060
2061 public void print( String data, String charset ) throws IOException, IllegalStateException
2062 {
2063 if( hasConnection() )
2064 {
2065 wrappedConnection.print( data, charset );
2066 }
2067 else
2068 {
2069 throw new IllegalStateException( "Connection has been released" );
2070 }
2071 }
2072
2073
2074
2075
2076
2077
2078
2079
2080 public void printLine( String data, String charset ) throws IOException, IllegalStateException
2081 {
2082 if( hasConnection() )
2083 {
2084 wrappedConnection.printLine( data, charset );
2085 }
2086 else
2087 {
2088 throw new IllegalStateException( "Connection has been released" );
2089 }
2090 }
2091
2092
2093
2094
2095
2096
2097 public void setSocketTimeout( int timeout ) throws SocketException, IllegalStateException
2098 {
2099 if( hasConnection() )
2100 {
2101 wrappedConnection.setSocketTimeout( timeout );
2102 }
2103 else
2104 {
2105 throw new IllegalStateException( "Connection has been released" );
2106 }
2107 }
2108
2109 public Socket getConnectionSocket()
2110 {
2111 if( wrappedConnection instanceof ConnectionWithSocket )
2112 return ( ( ConnectionWithSocket )wrappedConnection ).getConnectionSocket();
2113
2114 return null;
2115 }
2116
2117 }
2118
2119 }