Source Code Cross Referenced for MultiThreadedHttpConnectionManager.java in  » Net » Apache-common-HttpClient » org » apache » commons » httpclient » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » Apache common HttpClient » org.apache.commons.httpclient 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/MultiThreadedHttpConnectionManager.java,v 1.47 2004/12/21 11:27:55 olegk Exp $
0003:         * $Revision: 564906 $
0004:         * $Date: 2007-08-11 14:27:18 +0200 (Sat, 11 Aug 2007) $
0005:         *
0006:         * ====================================================================
0007:         *
0008:         *  Licensed to the Apache Software Foundation (ASF) under one or more
0009:         *  contributor license agreements.  See the NOTICE file distributed with
0010:         *  this work for additional information regarding copyright ownership.
0011:         *  The ASF licenses this file to You under the Apache License, Version 2.0
0012:         *  (the "License"); you may not use this file except in compliance with
0013:         *  the License.  You may obtain a copy of the License at
0014:         *
0015:         *      http://www.apache.org/licenses/LICENSE-2.0
0016:         *
0017:         *  Unless required by applicable law or agreed to in writing, software
0018:         *  distributed under the License is distributed on an "AS IS" BASIS,
0019:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0020:         *  See the License for the specific language governing permissions and
0021:         *  limitations under the License.
0022:         * ====================================================================
0023:         *
0024:         * This software consists of voluntary contributions made by many
0025:         * individuals on behalf of the Apache Software Foundation.  For more
0026:         * information on the Apache Software Foundation, please see
0027:         * <http://www.apache.org/>.
0028:         *
0029:         */
0030:
0031:        package org.apache.commons.httpclient;
0032:
0033:        import java.io.IOException;
0034:        import java.io.InputStream;
0035:        import java.io.OutputStream;
0036:        import java.lang.ref.Reference;
0037:        import java.lang.ref.ReferenceQueue;
0038:        import java.lang.ref.WeakReference;
0039:        import java.net.InetAddress;
0040:        import java.net.SocketException;
0041:        import java.util.ArrayList;
0042:        import java.util.HashMap;
0043:        import java.util.Iterator;
0044:        import java.util.LinkedList;
0045:        import java.util.Map;
0046:        import java.util.WeakHashMap;
0047:
0048:        import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
0049:        import org.apache.commons.httpclient.params.HttpConnectionParams;
0050:        import org.apache.commons.httpclient.protocol.Protocol;
0051:        import org.apache.commons.httpclient.util.IdleConnectionHandler;
0052:        import org.apache.commons.logging.Log;
0053:        import org.apache.commons.logging.LogFactory;
0054:
0055:        /**
0056:         * Manages a set of HttpConnections for various HostConfigurations.
0057:         *
0058:         * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
0059:         * @author Eric Johnson
0060:         * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
0061:         * @author Carl A. Dunham
0062:         *
0063:         * @since 2.0
0064:         */
0065:        public class MultiThreadedHttpConnectionManager implements 
0066:                HttpConnectionManager {
0067:
0068:            // -------------------------------------------------------- Class Variables
0069:
0070:            /** Log object for this class. */
0071:            private static final Log LOG = LogFactory
0072:                    .getLog(MultiThreadedHttpConnectionManager.class);
0073:
0074:            /** The default maximum number of connections allowed per host */
0075:            public static final int DEFAULT_MAX_HOST_CONNECTIONS = 2; // Per RFC 2616 sec 8.1.4
0076:
0077:            /** The default maximum number of connections allowed overall */
0078:            public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20;
0079:
0080:            /**
0081:             * A mapping from Reference to ConnectionSource.  Used to reclaim resources when connections
0082:             * are lost to the garbage collector.
0083:             */
0084:            private static final Map REFERENCE_TO_CONNECTION_SOURCE = new HashMap();
0085:
0086:            /**
0087:             * The reference queue used to track when HttpConnections are lost to the
0088:             * garbage collector
0089:             */
0090:            private static final ReferenceQueue REFERENCE_QUEUE = new ReferenceQueue();
0091:
0092:            /**
0093:             * The thread responsible for handling lost connections.
0094:             */
0095:            private static ReferenceQueueThread REFERENCE_QUEUE_THREAD;
0096:
0097:            /**
0098:             * Holds references to all active instances of this class.
0099:             */
0100:            private static WeakHashMap ALL_CONNECTION_MANAGERS = new WeakHashMap();
0101:
0102:            // ---------------------------------------------------------- Class Methods
0103:
0104:            /**
0105:             * Shuts down and cleans up resources used by all instances of 
0106:             * MultiThreadedHttpConnectionManager. All static resources are released, all threads are 
0107:             * stopped, and {@link #shutdown()} is called on all live instances of 
0108:             * MultiThreadedHttpConnectionManager.
0109:             *
0110:             * @see #shutdown()
0111:             */
0112:            public static void shutdownAll() {
0113:
0114:                synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
0115:                    // shutdown all connection managers
0116:                    synchronized (ALL_CONNECTION_MANAGERS) {
0117:                        // Don't use an iterator here. Iterators on WeakHashMap can
0118:                        // get ConcurrentModificationException on garbage collection.
0119:                        MultiThreadedHttpConnectionManager[] connManagers = (MultiThreadedHttpConnectionManager[]) ALL_CONNECTION_MANAGERS
0120:                                .keySet()
0121:                                .toArray(
0122:                                        new MultiThreadedHttpConnectionManager[ALL_CONNECTION_MANAGERS
0123:                                                .size()]);
0124:
0125:                        // The map may shrink after size() is called, or some entry
0126:                        // may get GCed while the array is built, so expect null.
0127:                        for (int i = 0; i < connManagers.length; i++) {
0128:                            if (connManagers[i] != null)
0129:                                connManagers[i].shutdown();
0130:                        }
0131:                    }
0132:
0133:                    // shutdown static resources
0134:                    if (REFERENCE_QUEUE_THREAD != null) {
0135:                        REFERENCE_QUEUE_THREAD.shutdown();
0136:                        REFERENCE_QUEUE_THREAD = null;
0137:                    }
0138:                    REFERENCE_TO_CONNECTION_SOURCE.clear();
0139:                }
0140:            }
0141:
0142:            /**
0143:             * Stores the reference to the given connection along with the host config and connection pool.  
0144:             * These values will be used to reclaim resources if the connection is lost to the garbage 
0145:             * collector.  This method should be called before a connection is released from the connection 
0146:             * manager.
0147:             * 
0148:             * <p>A static reference to the connection manager will also be stored.  To ensure that
0149:             * the connection manager can be GCed {@link #removeReferenceToConnection(HttpConnection)}
0150:             * should be called for all connections that the connection manager is storing a reference
0151:             * to.</p>
0152:             * 
0153:             * @param connection the connection to create a reference for
0154:             * @param hostConfiguration the connection's host config
0155:             * @param connectionPool the connection pool that created the connection
0156:             * 
0157:             * @see #removeReferenceToConnection(HttpConnection)
0158:             */
0159:            private static void storeReferenceToConnection(
0160:                    HttpConnectionWithReference connection,
0161:                    HostConfiguration hostConfiguration,
0162:                    ConnectionPool connectionPool) {
0163:
0164:                ConnectionSource source = new ConnectionSource();
0165:                source.connectionPool = connectionPool;
0166:                source.hostConfiguration = hostConfiguration;
0167:
0168:                synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
0169:
0170:                    // start the reference queue thread if needed
0171:                    if (REFERENCE_QUEUE_THREAD == null) {
0172:                        REFERENCE_QUEUE_THREAD = new ReferenceQueueThread();
0173:                        REFERENCE_QUEUE_THREAD.start();
0174:                    }
0175:
0176:                    REFERENCE_TO_CONNECTION_SOURCE.put(connection.reference,
0177:                            source);
0178:                }
0179:            }
0180:
0181:            /**
0182:             * Closes and releases all connections currently checked out of the given connection pool.
0183:             * @param connectionPool the connection pool to shutdown the connections for
0184:             */
0185:            private static void shutdownCheckedOutConnections(
0186:                    ConnectionPool connectionPool) {
0187:
0188:                // keep a list of the connections to be closed
0189:                ArrayList connectionsToClose = new ArrayList();
0190:
0191:                synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
0192:
0193:                    Iterator referenceIter = REFERENCE_TO_CONNECTION_SOURCE
0194:                            .keySet().iterator();
0195:                    while (referenceIter.hasNext()) {
0196:                        Reference ref = (Reference) referenceIter.next();
0197:                        ConnectionSource source = (ConnectionSource) REFERENCE_TO_CONNECTION_SOURCE
0198:                                .get(ref);
0199:                        if (source.connectionPool == connectionPool) {
0200:                            referenceIter.remove();
0201:                            HttpConnection connection = (HttpConnection) ref
0202:                                    .get();
0203:                            if (connection != null) {
0204:                                connectionsToClose.add(connection);
0205:                            }
0206:                        }
0207:                    }
0208:                }
0209:
0210:                // close and release the connections outside of the synchronized block to
0211:                // avoid holding the lock for too long
0212:                for (Iterator i = connectionsToClose.iterator(); i.hasNext();) {
0213:                    HttpConnection connection = (HttpConnection) i.next();
0214:                    connection.close();
0215:                    // remove the reference to the connection manager. this ensures
0216:                    // that the we don't accidentally end up here again
0217:                    connection.setHttpConnectionManager(null);
0218:                    connection.releaseConnection();
0219:                }
0220:            }
0221:
0222:            /**
0223:             * Removes the reference being stored for the given connection.  This method should be called
0224:             * when the connection manager again has a direct reference to the connection.
0225:             * 
0226:             * @param connection the connection to remove the reference for
0227:             * 
0228:             * @see #storeReferenceToConnection(HttpConnection, HostConfiguration, ConnectionPool)
0229:             */
0230:            private static void removeReferenceToConnection(
0231:                    HttpConnectionWithReference connection) {
0232:
0233:                synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
0234:                    REFERENCE_TO_CONNECTION_SOURCE.remove(connection.reference);
0235:                }
0236:            }
0237:
0238:            // ----------------------------------------------------- Instance Variables
0239:
0240:            /**
0241:             * Collection of parameters associated with this connection manager.
0242:             */
0243:            private HttpConnectionManagerParams params = new HttpConnectionManagerParams();
0244:
0245:            /** Connection Pool */
0246:            private ConnectionPool connectionPool;
0247:
0248:            private volatile boolean shutdown = false;
0249:
0250:            // ----------------------------------------------------------- Constructors
0251:
0252:            /**
0253:             * No-args constructor
0254:             */
0255:            public MultiThreadedHttpConnectionManager() {
0256:                this .connectionPool = new ConnectionPool();
0257:                synchronized (ALL_CONNECTION_MANAGERS) {
0258:                    ALL_CONNECTION_MANAGERS.put(this , null);
0259:                }
0260:            }
0261:
0262:            // ------------------------------------------------------- Instance Methods
0263:
0264:            /**
0265:             * Shuts down the connection manager and releases all resources.  All connections associated 
0266:             * with this class will be closed and released. 
0267:             * 
0268:             * <p>The connection manager can no longer be used once shut down.  
0269:             * 
0270:             * <p>Calling this method more than once will have no effect.
0271:             */
0272:            public synchronized void shutdown() {
0273:                synchronized (connectionPool) {
0274:                    if (!shutdown) {
0275:                        shutdown = true;
0276:                        connectionPool.shutdown();
0277:                    }
0278:                }
0279:            }
0280:
0281:            /**
0282:             * Gets the staleCheckingEnabled value to be set on HttpConnections that are created.
0283:             * 
0284:             * @return <code>true</code> if stale checking will be enabled on HttpConnections
0285:             * 
0286:             * @see HttpConnection#isStaleCheckingEnabled()
0287:             * 
0288:             * @deprecated Use {@link HttpConnectionManagerParams#isStaleCheckingEnabled()},
0289:             * {@link HttpConnectionManager#getParams()}.
0290:             */
0291:            public boolean isConnectionStaleCheckingEnabled() {
0292:                return this .params.isStaleCheckingEnabled();
0293:            }
0294:
0295:            /**
0296:             * Sets the staleCheckingEnabled value to be set on HttpConnections that are created.
0297:             * 
0298:             * @param connectionStaleCheckingEnabled <code>true</code> if stale checking will be enabled 
0299:             * on HttpConnections
0300:             * 
0301:             * @see HttpConnection#setStaleCheckingEnabled(boolean)
0302:             * 
0303:             * @deprecated Use {@link HttpConnectionManagerParams#setStaleCheckingEnabled(boolean)},
0304:             * {@link HttpConnectionManager#getParams()}.
0305:             */
0306:            public void setConnectionStaleCheckingEnabled(
0307:                    boolean connectionStaleCheckingEnabled) {
0308:                this .params
0309:                        .setStaleCheckingEnabled(connectionStaleCheckingEnabled);
0310:            }
0311:
0312:            /**
0313:             * Sets the maximum number of connections allowed for a given
0314:             * HostConfiguration. Per RFC 2616 section 8.1.4, this value defaults to 2.
0315:             *
0316:             * @param maxHostConnections the number of connections allowed for each
0317:             * hostConfiguration
0318:             * 
0319:             * @deprecated Use {@link HttpConnectionManagerParams#setDefaultMaxConnectionsPerHost(int)},
0320:             * {@link HttpConnectionManager#getParams()}.
0321:             */
0322:            public void setMaxConnectionsPerHost(int maxHostConnections) {
0323:                this .params.setDefaultMaxConnectionsPerHost(maxHostConnections);
0324:            }
0325:
0326:            /**
0327:             * Gets the maximum number of connections allowed for a given
0328:             * hostConfiguration.
0329:             *
0330:             * @return The maximum number of connections allowed for a given
0331:             * hostConfiguration.
0332:             * 
0333:             * @deprecated Use {@link HttpConnectionManagerParams#getDefaultMaxConnectionsPerHost()},
0334:             * {@link HttpConnectionManager#getParams()}.
0335:             */
0336:            public int getMaxConnectionsPerHost() {
0337:                return this .params.getDefaultMaxConnectionsPerHost();
0338:            }
0339:
0340:            /**
0341:             * Sets the maximum number of connections allowed for this connection manager.
0342:             *
0343:             * @param maxTotalConnections the maximum number of connections allowed
0344:             * 
0345:             * @deprecated Use {@link HttpConnectionManagerParams#setMaxTotalConnections(int)},
0346:             * {@link HttpConnectionManager#getParams()}.
0347:             */
0348:            public void setMaxTotalConnections(int maxTotalConnections) {
0349:                this .params.setMaxTotalConnections(maxTotalConnections);
0350:            }
0351:
0352:            /**
0353:             * Gets the maximum number of connections allowed for this connection manager.
0354:             *
0355:             * @return The maximum number of connections allowed
0356:             * 
0357:             * @deprecated Use {@link HttpConnectionManagerParams#getMaxTotalConnections()},
0358:             * {@link HttpConnectionManager#getParams()}.
0359:             */
0360:            public int getMaxTotalConnections() {
0361:                return this .params.getMaxTotalConnections();
0362:            }
0363:
0364:            /**
0365:             * @see HttpConnectionManager#getConnection(HostConfiguration)
0366:             */
0367:            public HttpConnection getConnection(
0368:                    HostConfiguration hostConfiguration) {
0369:
0370:                while (true) {
0371:                    try {
0372:                        return getConnectionWithTimeout(hostConfiguration, 0);
0373:                    } catch (ConnectionPoolTimeoutException e) {
0374:                        // we'll go ahead and log this, but it should never happen. HttpExceptions
0375:                        // are only thrown when the timeout occurs and since we have no timeout
0376:                        // it should never happen.
0377:                        LOG
0378:                                .debug(
0379:                                        "Unexpected exception while waiting for connection",
0380:                                        e);
0381:                    }
0382:                }
0383:            }
0384:
0385:            /**
0386:             * Gets a connection or waits if one is not available.  A connection is
0387:             * available if one exists that is not being used or if fewer than
0388:             * maxHostConnections have been created in the connectionPool, and fewer
0389:             * than maxTotalConnections have been created in all connectionPools.
0390:             *
0391:             * @param hostConfiguration The host configuration specifying the connection
0392:             *        details.
0393:             * @param timeout the number of milliseconds to wait for a connection, 0 to
0394:             * wait indefinitely
0395:             *
0396:             * @return HttpConnection an available connection
0397:             *
0398:             * @throws HttpException if a connection does not become available in
0399:             * 'timeout' milliseconds
0400:             * 
0401:             * @since 3.0
0402:             */
0403:            public HttpConnection getConnectionWithTimeout(
0404:                    HostConfiguration hostConfiguration, long timeout)
0405:                    throws ConnectionPoolTimeoutException {
0406:
0407:                LOG
0408:                        .trace("enter HttpConnectionManager.getConnectionWithTimeout(HostConfiguration, long)");
0409:
0410:                if (hostConfiguration == null) {
0411:                    throw new IllegalArgumentException(
0412:                            "hostConfiguration is null");
0413:                }
0414:
0415:                if (LOG.isDebugEnabled()) {
0416:                    LOG.debug("HttpConnectionManager.getConnection:  config = "
0417:                            + hostConfiguration + ", timeout = " + timeout);
0418:                }
0419:
0420:                final HttpConnection conn = doGetConnection(hostConfiguration,
0421:                        timeout);
0422:
0423:                // wrap the connection in an adapter so we can ensure it is used 
0424:                // only once
0425:                return new HttpConnectionAdapter(conn);
0426:            }
0427:
0428:            /**
0429:             * @see HttpConnectionManager#getConnection(HostConfiguration, long)
0430:             * 
0431:             * @deprecated Use #getConnectionWithTimeout(HostConfiguration, long)
0432:             */
0433:            public HttpConnection getConnection(
0434:                    HostConfiguration hostConfiguration, long timeout)
0435:                    throws HttpException {
0436:
0437:                LOG
0438:                        .trace("enter HttpConnectionManager.getConnection(HostConfiguration, long)");
0439:                try {
0440:                    return getConnectionWithTimeout(hostConfiguration, timeout);
0441:                } catch (ConnectionPoolTimeoutException e) {
0442:                    throw new HttpException(e.getMessage());
0443:                }
0444:            }
0445:
0446:            private HttpConnection doGetConnection(
0447:                    HostConfiguration hostConfiguration, long timeout)
0448:                    throws ConnectionPoolTimeoutException {
0449:
0450:                HttpConnection connection = null;
0451:
0452:                int maxHostConnections = this .params
0453:                        .getMaxConnectionsPerHost(hostConfiguration);
0454:                int maxTotalConnections = this .params.getMaxTotalConnections();
0455:
0456:                synchronized (connectionPool) {
0457:
0458:                    // we clone the hostConfiguration
0459:                    // so that it cannot be changed once the connection has been retrieved
0460:                    hostConfiguration = new HostConfiguration(hostConfiguration);
0461:                    HostConnectionPool hostPool = connectionPool.getHostPool(
0462:                            hostConfiguration, true);
0463:                    WaitingThread waitingThread = null;
0464:
0465:                    boolean useTimeout = (timeout > 0);
0466:                    long timeToWait = timeout;
0467:                    long startWait = 0;
0468:                    long endWait = 0;
0469:
0470:                    while (connection == null) {
0471:
0472:                        if (shutdown) {
0473:                            throw new IllegalStateException(
0474:                                    "Connection factory has been shutdown.");
0475:                        }
0476:
0477:                        // happen to have a free connection with the right specs
0478:                        //
0479:                        if (hostPool.freeConnections.size() > 0) {
0480:                            connection = connectionPool
0481:                                    .getFreeConnection(hostConfiguration);
0482:
0483:                            // have room to make more
0484:                            //
0485:                        } else if ((hostPool.numConnections < maxHostConnections)
0486:                                && (connectionPool.numConnections < maxTotalConnections)) {
0487:
0488:                            connection = connectionPool
0489:                                    .createConnection(hostConfiguration);
0490:
0491:                            // have room to add host connection, and there is at least one free
0492:                            // connection that can be liberated to make overall room
0493:                            //
0494:                        } else if ((hostPool.numConnections < maxHostConnections)
0495:                                && (connectionPool.freeConnections.size() > 0)) {
0496:
0497:                            connectionPool.deleteLeastUsedConnection();
0498:                            connection = connectionPool
0499:                                    .createConnection(hostConfiguration);
0500:
0501:                            // otherwise, we have to wait for one of the above conditions to
0502:                            // become true
0503:                            //
0504:                        } else {
0505:                            // TODO: keep track of which hostConfigurations have waiting
0506:                            // threads, so they avoid being sacrificed before necessary
0507:
0508:                            try {
0509:
0510:                                if (useTimeout && timeToWait <= 0) {
0511:                                    throw new ConnectionPoolTimeoutException(
0512:                                            "Timeout waiting for connection");
0513:                                }
0514:
0515:                                if (LOG.isDebugEnabled()) {
0516:                                    LOG
0517:                                            .debug("Unable to get a connection, waiting..., hostConfig="
0518:                                                    + hostConfiguration);
0519:                                }
0520:
0521:                                if (waitingThread == null) {
0522:                                    waitingThread = new WaitingThread();
0523:                                    waitingThread.hostConnectionPool = hostPool;
0524:                                    waitingThread.thread = Thread
0525:                                            .currentThread();
0526:                                } else {
0527:                                    waitingThread.interruptedByConnectionPool = false;
0528:                                }
0529:
0530:                                if (useTimeout) {
0531:                                    startWait = System.currentTimeMillis();
0532:                                }
0533:
0534:                                hostPool.waitingThreads.addLast(waitingThread);
0535:                                connectionPool.waitingThreads
0536:                                        .addLast(waitingThread);
0537:                                connectionPool.wait(timeToWait);
0538:                            } catch (InterruptedException e) {
0539:                                if (!waitingThread.interruptedByConnectionPool) {
0540:                                    LOG
0541:                                            .debug(
0542:                                                    "Interrupted while waiting for connection",
0543:                                                    e);
0544:                                    throw new IllegalThreadStateException(
0545:                                            "Interrupted while waiting in MultiThreadedHttpConnectionManager");
0546:                                }
0547:                                // Else, do nothing, we were interrupted by the connection pool
0548:                                // and should now have a connection waiting for us, continue
0549:                                // in the loop and let's get it.
0550:                            } finally {
0551:                                if (!waitingThread.interruptedByConnectionPool) {
0552:                                    // Either we timed out, experienced a "spurious wakeup", or were
0553:                                    // interrupted by an external thread.  Regardless we need to 
0554:                                    // cleanup for ourselves in the wait queue.
0555:                                    hostPool.waitingThreads
0556:                                            .remove(waitingThread);
0557:                                    connectionPool.waitingThreads
0558:                                            .remove(waitingThread);
0559:                                }
0560:
0561:                                if (useTimeout) {
0562:                                    endWait = System.currentTimeMillis();
0563:                                    timeToWait -= (endWait - startWait);
0564:                                }
0565:                            }
0566:                        }
0567:                    }
0568:                }
0569:                return connection;
0570:            }
0571:
0572:            /**
0573:             * Gets the total number of pooled connections for the given host configuration.  This 
0574:             * is the total number of connections that have been created and are still in use 
0575:             * by this connection manager for the host configuration.  This value will
0576:             * not exceed the {@link #getMaxConnectionsPerHost() maximum number of connections per
0577:             * host}.
0578:             * 
0579:             * @param hostConfiguration The host configuration
0580:             * @return The total number of pooled connections
0581:             */
0582:            public int getConnectionsInPool(HostConfiguration hostConfiguration) {
0583:                synchronized (connectionPool) {
0584:                    HostConnectionPool hostPool = connectionPool.getHostPool(
0585:                            hostConfiguration, false);
0586:                    return (hostPool != null) ? hostPool.numConnections : 0;
0587:                }
0588:            }
0589:
0590:            /**
0591:             * Gets the total number of pooled connections.  This is the total number of 
0592:             * connections that have been created and are still in use by this connection 
0593:             * manager.  This value will not exceed the {@link #getMaxTotalConnections() 
0594:             * maximum number of connections}.
0595:             * 
0596:             * @return the total number of pooled connections
0597:             */
0598:            public int getConnectionsInPool() {
0599:                synchronized (connectionPool) {
0600:                    return connectionPool.numConnections;
0601:                }
0602:            }
0603:
0604:            /**
0605:             * Gets the number of connections in use for this configuration.
0606:             *
0607:             * @param hostConfiguration the key that connections are tracked on
0608:             * @return the number of connections in use
0609:             * 
0610:             * @deprecated Use {@link #getConnectionsInPool(HostConfiguration)}
0611:             */
0612:            public int getConnectionsInUse(HostConfiguration hostConfiguration) {
0613:                return getConnectionsInPool(hostConfiguration);
0614:            }
0615:
0616:            /**
0617:             * Gets the total number of connections in use.
0618:             * 
0619:             * @return the total number of connections in use
0620:             * 
0621:             * @deprecated Use {@link #getConnectionsInPool()}
0622:             */
0623:            public int getConnectionsInUse() {
0624:                return getConnectionsInPool();
0625:            }
0626:
0627:            /**
0628:             * Deletes all closed connections.  Only connections currently owned by the connection
0629:             * manager are processed.
0630:             * 
0631:             * @see HttpConnection#isOpen()
0632:             * 
0633:             * @since 3.0
0634:             */
0635:            public void deleteClosedConnections() {
0636:                connectionPool.deleteClosedConnections();
0637:            }
0638:
0639:            /**
0640:             * @since 3.0
0641:             */
0642:            public void closeIdleConnections(long idleTimeout) {
0643:                connectionPool.closeIdleConnections(idleTimeout);
0644:                deleteClosedConnections();
0645:            }
0646:
0647:            /**
0648:             * Make the given HttpConnection available for use by other requests.
0649:             * If another thread is blocked in getConnection() that could use this
0650:             * connection, it will be woken up.
0651:             *
0652:             * @param conn the HttpConnection to make available.
0653:             */
0654:            public void releaseConnection(HttpConnection conn) {
0655:                LOG
0656:                        .trace("enter HttpConnectionManager.releaseConnection(HttpConnection)");
0657:
0658:                if (conn instanceof  HttpConnectionAdapter) {
0659:                    // connections given out are wrapped in an HttpConnectionAdapter
0660:                    conn = ((HttpConnectionAdapter) conn)
0661:                            .getWrappedConnection();
0662:                } else {
0663:                    // this is okay, when an HttpConnectionAdapter is released
0664:                    // is releases the real connection
0665:                }
0666:
0667:                // make sure that the response has been read.
0668:                SimpleHttpConnectionManager.finishLastResponse(conn);
0669:
0670:                connectionPool.freeConnection(conn);
0671:            }
0672:
0673:            /**
0674:             * Gets the host configuration for a connection.
0675:             * @param conn the connection to get the configuration of
0676:             * @return a new HostConfiguration
0677:             */
0678:            private HostConfiguration configurationForConnection(
0679:                    HttpConnection conn) {
0680:
0681:                HostConfiguration connectionConfiguration = new HostConfiguration();
0682:
0683:                connectionConfiguration.setHost(conn.getHost(), conn.getPort(),
0684:                        conn.getProtocol());
0685:                if (conn.getLocalAddress() != null) {
0686:                    connectionConfiguration.setLocalAddress(conn
0687:                            .getLocalAddress());
0688:                }
0689:                if (conn.getProxyHost() != null) {
0690:                    connectionConfiguration.setProxy(conn.getProxyHost(), conn
0691:                            .getProxyPort());
0692:                }
0693:
0694:                return connectionConfiguration;
0695:            }
0696:
0697:            /**
0698:             * Returns {@link HttpConnectionManagerParams parameters} associated 
0699:             * with this connection manager.
0700:             * 
0701:             * @since 3.0
0702:             * 
0703:             * @see HttpConnectionManagerParams
0704:             */
0705:            public HttpConnectionManagerParams getParams() {
0706:                return this .params;
0707:            }
0708:
0709:            /**
0710:             * Assigns {@link HttpConnectionManagerParams parameters} for this 
0711:             * connection manager.
0712:             * 
0713:             * @since 3.0
0714:             * 
0715:             * @see HttpConnectionManagerParams
0716:             */
0717:            public void setParams(final HttpConnectionManagerParams params) {
0718:                if (params == null) {
0719:                    throw new IllegalArgumentException(
0720:                            "Parameters may not be null");
0721:                }
0722:                this .params = params;
0723:            }
0724:
0725:            /**
0726:             * Global Connection Pool, including per-host pools
0727:             */
0728:            private class ConnectionPool {
0729:
0730:                /** The list of free connections */
0731:                private LinkedList freeConnections = new LinkedList();
0732:
0733:                /** The list of WaitingThreads waiting for a connection */
0734:                private LinkedList waitingThreads = new LinkedList();
0735:
0736:                /**
0737:                 * Map where keys are {@link HostConfiguration}s and values are {@link
0738:                 * HostConnectionPool}s
0739:                 */
0740:                private final Map mapHosts = new HashMap();
0741:
0742:                private IdleConnectionHandler idleConnectionHandler = new IdleConnectionHandler();
0743:
0744:                /** The number of created connections */
0745:                private int numConnections = 0;
0746:
0747:                /**
0748:                 * Cleans up all connection pool resources.
0749:                 */
0750:                public synchronized void shutdown() {
0751:
0752:                    // close all free connections
0753:                    Iterator iter = freeConnections.iterator();
0754:                    while (iter.hasNext()) {
0755:                        HttpConnection conn = (HttpConnection) iter.next();
0756:                        iter.remove();
0757:                        conn.close();
0758:                    }
0759:
0760:                    // close all connections that have been checked out
0761:                    shutdownCheckedOutConnections(this );
0762:
0763:                    // interrupt all waiting threads
0764:                    iter = waitingThreads.iterator();
0765:                    while (iter.hasNext()) {
0766:                        WaitingThread waiter = (WaitingThread) iter.next();
0767:                        iter.remove();
0768:                        waiter.interruptedByConnectionPool = true;
0769:                        waiter.thread.interrupt();
0770:                    }
0771:
0772:                    // clear out map hosts
0773:                    mapHosts.clear();
0774:
0775:                    // remove all references to connections
0776:                    idleConnectionHandler.removeAll();
0777:                }
0778:
0779:                /**
0780:                 * Creates a new connection and returns it for use of the calling method.
0781:                 *
0782:                 * @param hostConfiguration the configuration for the connection
0783:                 * @return a new connection or <code>null</code> if none are available
0784:                 */
0785:                public synchronized HttpConnection createConnection(
0786:                        HostConfiguration hostConfiguration) {
0787:                    HostConnectionPool hostPool = getHostPool(
0788:                            hostConfiguration, true);
0789:                    if (LOG.isDebugEnabled()) {
0790:                        LOG.debug("Allocating new connection, hostConfig="
0791:                                + hostConfiguration);
0792:                    }
0793:                    HttpConnectionWithReference connection = new HttpConnectionWithReference(
0794:                            hostConfiguration);
0795:                    connection.getParams().setDefaults(
0796:                            MultiThreadedHttpConnectionManager.this .params);
0797:                    connection
0798:                            .setHttpConnectionManager(MultiThreadedHttpConnectionManager.this );
0799:                    numConnections++;
0800:                    hostPool.numConnections++;
0801:
0802:                    // store a reference to this connection so that it can be cleaned up
0803:                    // in the event it is not correctly released
0804:                    storeReferenceToConnection(connection, hostConfiguration,
0805:                            this );
0806:                    return connection;
0807:                }
0808:
0809:                /**
0810:                 * Handles cleaning up for a lost connection with the given config.  Decrements any 
0811:                 * connection counts and notifies waiting threads, if appropriate.
0812:                 * 
0813:                 * @param config the host configuration of the connection that was lost
0814:                 */
0815:                public synchronized void handleLostConnection(
0816:                        HostConfiguration config) {
0817:                    HostConnectionPool hostPool = getHostPool(config, true);
0818:                    hostPool.numConnections--;
0819:                    if ((hostPool.numConnections == 0)
0820:                            && hostPool.waitingThreads.isEmpty()) {
0821:
0822:                        mapHosts.remove(config);
0823:                    }
0824:
0825:                    numConnections--;
0826:                    notifyWaitingThread(config);
0827:                }
0828:
0829:                /**
0830:                 * Get the pool (list) of connections available for the given hostConfig.
0831:                 *
0832:                 * @param hostConfiguration the configuraton for the connection pool
0833:                 * @param create <code>true</code> to create a pool if not found,
0834:                 *               <code>false</code> to return <code>null</code>
0835:                 *
0836:                 * @return a pool (list) of connections available for the given config,
0837:                 *         or <code>null</code> if neither found nor created
0838:                 */
0839:                public synchronized HostConnectionPool getHostPool(
0840:                        HostConfiguration hostConfiguration, boolean create) {
0841:                    LOG
0842:                            .trace("enter HttpConnectionManager.ConnectionPool.getHostPool(HostConfiguration)");
0843:
0844:                    // Look for a list of connections for the given config
0845:                    HostConnectionPool listConnections = (HostConnectionPool) mapHosts
0846:                            .get(hostConfiguration);
0847:                    if ((listConnections == null) && create) {
0848:                        // First time for this config
0849:                        listConnections = new HostConnectionPool();
0850:                        listConnections.hostConfiguration = hostConfiguration;
0851:                        mapHosts.put(hostConfiguration, listConnections);
0852:                    }
0853:
0854:                    return listConnections;
0855:                }
0856:
0857:                /**
0858:                 * If available, get a free connection for this host
0859:                 *
0860:                 * @param hostConfiguration the configuraton for the connection pool
0861:                 * @return an available connection for the given config
0862:                 */
0863:                public synchronized HttpConnection getFreeConnection(
0864:                        HostConfiguration hostConfiguration) {
0865:
0866:                    HttpConnectionWithReference connection = null;
0867:
0868:                    HostConnectionPool hostPool = getHostPool(
0869:                            hostConfiguration, false);
0870:
0871:                    if ((hostPool != null)
0872:                            && (hostPool.freeConnections.size() > 0)) {
0873:                        connection = (HttpConnectionWithReference) hostPool.freeConnections
0874:                                .removeLast();
0875:                        freeConnections.remove(connection);
0876:                        // store a reference to this connection so that it can be cleaned up
0877:                        // in the event it is not correctly released
0878:                        storeReferenceToConnection(connection,
0879:                                hostConfiguration, this );
0880:                        if (LOG.isDebugEnabled()) {
0881:                            LOG.debug("Getting free connection, hostConfig="
0882:                                    + hostConfiguration);
0883:                        }
0884:
0885:                        // remove the connection from the timeout handler
0886:                        idleConnectionHandler.remove(connection);
0887:                    } else if (LOG.isDebugEnabled()) {
0888:                        LOG
0889:                                .debug("There were no free connections to get, hostConfig="
0890:                                        + hostConfiguration);
0891:                    }
0892:                    return connection;
0893:                }
0894:
0895:                /**
0896:                 * Deletes all closed connections.
0897:                 */
0898:                public synchronized void deleteClosedConnections() {
0899:
0900:                    Iterator iter = freeConnections.iterator();
0901:
0902:                    while (iter.hasNext()) {
0903:                        HttpConnection conn = (HttpConnection) iter.next();
0904:                        if (!conn.isOpen()) {
0905:                            iter.remove();
0906:                            deleteConnection(conn);
0907:                        }
0908:                    }
0909:                }
0910:
0911:                /**
0912:                 * Closes idle connections.
0913:                 * @param idleTimeout
0914:                 */
0915:                public synchronized void closeIdleConnections(long idleTimeout) {
0916:                    idleConnectionHandler.closeIdleConnections(idleTimeout);
0917:                }
0918:
0919:                /**
0920:                 * Deletes the given connection.  This will remove all reference to the connection
0921:                 * so that it can be GCed.
0922:                 * 
0923:                 * <p><b>Note:</b> Does not remove the connection from the freeConnections list.  It
0924:                 * is assumed that the caller has already handled this case.</p>
0925:                 * 
0926:                 * @param connection The connection to delete
0927:                 */
0928:                private synchronized void deleteConnection(
0929:                        HttpConnection connection) {
0930:
0931:                    HostConfiguration connectionConfiguration = configurationForConnection(connection);
0932:
0933:                    if (LOG.isDebugEnabled()) {
0934:                        LOG.debug("Reclaiming connection, hostConfig="
0935:                                + connectionConfiguration);
0936:                    }
0937:
0938:                    connection.close();
0939:
0940:                    HostConnectionPool hostPool = getHostPool(
0941:                            connectionConfiguration, true);
0942:
0943:                    hostPool.freeConnections.remove(connection);
0944:                    hostPool.numConnections--;
0945:                    numConnections--;
0946:                    if ((hostPool.numConnections == 0)
0947:                            && hostPool.waitingThreads.isEmpty()) {
0948:
0949:                        mapHosts.remove(connectionConfiguration);
0950:                    }
0951:
0952:                    // remove the connection from the timeout handler
0953:                    idleConnectionHandler.remove(connection);
0954:                }
0955:
0956:                /**
0957:                 * Close and delete an old, unused connection to make room for a new one.
0958:                 */
0959:                public synchronized void deleteLeastUsedConnection() {
0960:
0961:                    HttpConnection connection = (HttpConnection) freeConnections
0962:                            .removeFirst();
0963:
0964:                    if (connection != null) {
0965:                        deleteConnection(connection);
0966:                    } else if (LOG.isDebugEnabled()) {
0967:                        LOG
0968:                                .debug("Attempted to reclaim an unused connection but there were none.");
0969:                    }
0970:                }
0971:
0972:                /**
0973:                 * Notifies a waiting thread that a connection for the given configuration is 
0974:                 * available.
0975:                 * @param configuration the host config to use for notifying
0976:                 * @see #notifyWaitingThread(HostConnectionPool)
0977:                 */
0978:                public synchronized void notifyWaitingThread(
0979:                        HostConfiguration configuration) {
0980:                    notifyWaitingThread(getHostPool(configuration, true));
0981:                }
0982:
0983:                /**
0984:                 * Notifies a waiting thread that a connection for the given configuration is 
0985:                 * available.  This will wake a thread waiting in this host pool or if there is not
0986:                 * one a thread in the connection pool will be notified.
0987:                 * 
0988:                 * @param hostPool the host pool to use for notifying
0989:                 */
0990:                public synchronized void notifyWaitingThread(
0991:                        HostConnectionPool hostPool) {
0992:
0993:                    // find the thread we are going to notify, we want to ensure that each
0994:                    // waiting thread is only interrupted once so we will remove it from 
0995:                    // all wait queues before interrupting it
0996:                    WaitingThread waitingThread = null;
0997:
0998:                    if (hostPool.waitingThreads.size() > 0) {
0999:                        if (LOG.isDebugEnabled()) {
1000:                            LOG
1001:                                    .debug("Notifying thread waiting on host pool, hostConfig="
1002:                                            + hostPool.hostConfiguration);
1003:                        }
1004:                        waitingThread = (WaitingThread) hostPool.waitingThreads
1005:                                .removeFirst();
1006:                        waitingThreads.remove(waitingThread);
1007:                    } else if (waitingThreads.size() > 0) {
1008:                        if (LOG.isDebugEnabled()) {
1009:                            LOG
1010:                                    .debug("No-one waiting on host pool, notifying next waiting thread.");
1011:                        }
1012:                        waitingThread = (WaitingThread) waitingThreads
1013:                                .removeFirst();
1014:                        waitingThread.hostConnectionPool.waitingThreads
1015:                                .remove(waitingThread);
1016:                    } else if (LOG.isDebugEnabled()) {
1017:                        LOG
1018:                                .debug("Notifying no-one, there are no waiting threads");
1019:                    }
1020:
1021:                    if (waitingThread != null) {
1022:                        waitingThread.interruptedByConnectionPool = true;
1023:                        waitingThread.thread.interrupt();
1024:                    }
1025:                }
1026:
1027:                /**
1028:                 * Marks the given connection as free.
1029:                 * @param conn a connection that is no longer being used
1030:                 */
1031:                public void freeConnection(HttpConnection conn) {
1032:
1033:                    HostConfiguration connectionConfiguration = configurationForConnection(conn);
1034:
1035:                    if (LOG.isDebugEnabled()) {
1036:                        LOG.debug("Freeing connection, hostConfig="
1037:                                + connectionConfiguration);
1038:                    }
1039:
1040:                    synchronized (this ) {
1041:
1042:                        if (shutdown) {
1043:                            // the connection manager has been shutdown, release the connection's
1044:                            // resources and get out of here
1045:                            conn.close();
1046:                            return;
1047:                        }
1048:
1049:                        HostConnectionPool hostPool = getHostPool(
1050:                                connectionConfiguration, true);
1051:
1052:                        // Put the connect back in the available list and notify a waiter
1053:                        hostPool.freeConnections.add(conn);
1054:                        if (hostPool.numConnections == 0) {
1055:                            // for some reason this connection pool didn't already exist
1056:                            LOG
1057:                                    .error("Host connection pool not found, hostConfig="
1058:                                            + connectionConfiguration);
1059:                            hostPool.numConnections = 1;
1060:                        }
1061:
1062:                        freeConnections.add(conn);
1063:                        // we can remove the reference to this connection as we have control over
1064:                        // it again.  this also ensures that the connection manager can be GCed
1065:                        removeReferenceToConnection((HttpConnectionWithReference) conn);
1066:                        if (numConnections == 0) {
1067:                            // for some reason this connection pool didn't already exist
1068:                            LOG
1069:                                    .error("Host connection pool not found, hostConfig="
1070:                                            + connectionConfiguration);
1071:                            numConnections = 1;
1072:                        }
1073:
1074:                        // register the connection with the timeout handler
1075:                        idleConnectionHandler.add(conn);
1076:
1077:                        notifyWaitingThread(hostPool);
1078:                    }
1079:                }
1080:            }
1081:
1082:            /**
1083:             * A simple struct-like class to combine the objects needed to release a connection's
1084:             * resources when claimed by the garbage collector.
1085:             */
1086:            private static class ConnectionSource {
1087:
1088:                /** The connection pool that created the connection */
1089:                public ConnectionPool connectionPool;
1090:
1091:                /** The connection's host configuration */
1092:                public HostConfiguration hostConfiguration;
1093:            }
1094:
1095:            /**
1096:             * A simple struct-like class to combine the connection list and the count
1097:             * of created connections.
1098:             */
1099:            private static class HostConnectionPool {
1100:                /** The hostConfig this pool is for */
1101:                public HostConfiguration hostConfiguration;
1102:
1103:                /** The list of free connections */
1104:                public LinkedList freeConnections = new LinkedList();
1105:
1106:                /** The list of WaitingThreads for this host */
1107:                public LinkedList waitingThreads = new LinkedList();
1108:
1109:                /** The number of created connections */
1110:                public int numConnections = 0;
1111:            }
1112:
1113:            /**
1114:             * A simple struct-like class to combine the waiting thread and the connection 
1115:             * pool it is waiting on.
1116:             */
1117:            private static class WaitingThread {
1118:                /** The thread that is waiting for a connection */
1119:                public Thread thread;
1120:
1121:                /** The connection pool the thread is waiting for */
1122:                public HostConnectionPool hostConnectionPool;
1123:
1124:                /** Flag to indicate if the thread was interrupted by the ConnectionPool. Set
1125:                 * to true inside {@link ConnectionPool#notifyWaitingThread(HostConnectionPool)} 
1126:                 * before the thread is interrupted. */
1127:                public boolean interruptedByConnectionPool = false;
1128:            }
1129:
1130:            /**
1131:             * A thread for listening for HttpConnections reclaimed by the garbage
1132:             * collector.
1133:             */
1134:            private static class ReferenceQueueThread extends Thread {
1135:
1136:                private volatile boolean shutdown = false;
1137:
1138:                /**
1139:                 * Create an instance and make this a daemon thread.
1140:                 */
1141:                public ReferenceQueueThread() {
1142:                    setDaemon(true);
1143:                    setName("MultiThreadedHttpConnectionManager cleanup");
1144:                }
1145:
1146:                public void shutdown() {
1147:                    this .shutdown = true;
1148:                    this .interrupt();
1149:                }
1150:
1151:                /**
1152:                 * Handles cleaning up for the given connection reference.
1153:                 * 
1154:                 * @param ref the reference to clean up
1155:                 */
1156:                private void handleReference(Reference ref) {
1157:
1158:                    ConnectionSource source = null;
1159:
1160:                    synchronized (REFERENCE_TO_CONNECTION_SOURCE) {
1161:                        source = (ConnectionSource) REFERENCE_TO_CONNECTION_SOURCE
1162:                                .remove(ref);
1163:                    }
1164:                    // only clean up for this reference if it is still associated with 
1165:                    // a ConnectionSource
1166:                    if (source != null) {
1167:                        if (LOG.isDebugEnabled()) {
1168:                            LOG
1169:                                    .debug("Connection reclaimed by garbage collector, hostConfig="
1170:                                            + source.hostConfiguration);
1171:                        }
1172:
1173:                        source.connectionPool
1174:                                .handleLostConnection(source.hostConfiguration);
1175:                    }
1176:                }
1177:
1178:                /**
1179:                 * Start execution.
1180:                 */
1181:                public void run() {
1182:                    while (!shutdown) {
1183:                        try {
1184:                            // remove the next reference and process it
1185:                            Reference ref = REFERENCE_QUEUE.remove();
1186:                            if (ref != null) {
1187:                                handleReference(ref);
1188:                            }
1189:                        } catch (InterruptedException e) {
1190:                            LOG.debug("ReferenceQueueThread interrupted", e);
1191:                        }
1192:                    }
1193:                }
1194:
1195:            }
1196:
1197:            /**
1198:             * A connection that keeps a reference to itself.
1199:             */
1200:            private static class HttpConnectionWithReference extends
1201:                    HttpConnection {
1202:
1203:                public WeakReference reference = new WeakReference(this ,
1204:                        REFERENCE_QUEUE);
1205:
1206:                /**
1207:                 * @param hostConfiguration
1208:                 */
1209:                public HttpConnectionWithReference(
1210:                        HostConfiguration hostConfiguration) {
1211:                    super (hostConfiguration);
1212:                }
1213:
1214:            }
1215:
1216:            /**
1217:             * An HttpConnection wrapper that ensures a connection cannot be used
1218:             * once released.
1219:             */
1220:            private static class HttpConnectionAdapter extends HttpConnection {
1221:
1222:                // the wrapped connection
1223:                private HttpConnection wrappedConnection;
1224:
1225:                /**
1226:                 * Creates a new HttpConnectionAdapter.
1227:                 * @param connection the connection to be wrapped
1228:                 */
1229:                public HttpConnectionAdapter(HttpConnection connection) {
1230:                    super (connection.getHost(), connection.getPort(),
1231:                            connection.getProtocol());
1232:                    this .wrappedConnection = connection;
1233:                }
1234:
1235:                /**
1236:                 * Tests if the wrapped connection is still available.
1237:                 * @return boolean
1238:                 */
1239:                protected boolean hasConnection() {
1240:                    return wrappedConnection != null;
1241:                }
1242:
1243:                /**
1244:                 * @return HttpConnection
1245:                 */
1246:                HttpConnection getWrappedConnection() {
1247:                    return wrappedConnection;
1248:                }
1249:
1250:                public void close() {
1251:                    if (hasConnection()) {
1252:                        wrappedConnection.close();
1253:                    } else {
1254:                        // do nothing
1255:                    }
1256:                }
1257:
1258:                public InetAddress getLocalAddress() {
1259:                    if (hasConnection()) {
1260:                        return wrappedConnection.getLocalAddress();
1261:                    } else {
1262:                        return null;
1263:                    }
1264:                }
1265:
1266:                /**
1267:                 * @deprecated
1268:                 */
1269:                public boolean isStaleCheckingEnabled() {
1270:                    if (hasConnection()) {
1271:                        return wrappedConnection.isStaleCheckingEnabled();
1272:                    } else {
1273:                        return false;
1274:                    }
1275:                }
1276:
1277:                public void setLocalAddress(InetAddress localAddress) {
1278:                    if (hasConnection()) {
1279:                        wrappedConnection.setLocalAddress(localAddress);
1280:                    } else {
1281:                        throw new IllegalStateException(
1282:                                "Connection has been released");
1283:                    }
1284:                }
1285:
1286:                /**
1287:                 * @deprecated 
1288:                 */
1289:                public void setStaleCheckingEnabled(boolean staleCheckEnabled) {
1290:                    if (hasConnection()) {
1291:                        wrappedConnection
1292:                                .setStaleCheckingEnabled(staleCheckEnabled);
1293:                    } else {
1294:                        throw new IllegalStateException(
1295:                                "Connection has been released");
1296:                    }
1297:                }
1298:
1299:                public String getHost() {
1300:                    if (hasConnection()) {
1301:                        return wrappedConnection.getHost();
1302:                    } else {
1303:                        return null;
1304:                    }
1305:                }
1306:
1307:                public HttpConnectionManager getHttpConnectionManager() {
1308:                    if (hasConnection()) {
1309:                        return wrappedConnection.getHttpConnectionManager();
1310:                    } else {
1311:                        return null;
1312:                    }
1313:                }
1314:
1315:                public InputStream getLastResponseInputStream() {
1316:                    if (hasConnection()) {
1317:                        return wrappedConnection.getLastResponseInputStream();
1318:                    } else {
1319:                        return null;
1320:                    }
1321:                }
1322:
1323:                public int getPort() {
1324:                    if (hasConnection()) {
1325:                        return wrappedConnection.getPort();
1326:                    } else {
1327:                        return -1;
1328:                    }
1329:                }
1330:
1331:                public Protocol getProtocol() {
1332:                    if (hasConnection()) {
1333:                        return wrappedConnection.getProtocol();
1334:                    } else {
1335:                        return null;
1336:                    }
1337:                }
1338:
1339:                public String getProxyHost() {
1340:                    if (hasConnection()) {
1341:                        return wrappedConnection.getProxyHost();
1342:                    } else {
1343:                        return null;
1344:                    }
1345:                }
1346:
1347:                public int getProxyPort() {
1348:                    if (hasConnection()) {
1349:                        return wrappedConnection.getProxyPort();
1350:                    } else {
1351:                        return -1;
1352:                    }
1353:                }
1354:
1355:                public OutputStream getRequestOutputStream()
1356:                        throws IOException, IllegalStateException {
1357:                    if (hasConnection()) {
1358:                        return wrappedConnection.getRequestOutputStream();
1359:                    } else {
1360:                        return null;
1361:                    }
1362:                }
1363:
1364:                public InputStream getResponseInputStream() throws IOException,
1365:                        IllegalStateException {
1366:                    if (hasConnection()) {
1367:                        return wrappedConnection.getResponseInputStream();
1368:                    } else {
1369:                        return null;
1370:                    }
1371:                }
1372:
1373:                public boolean isOpen() {
1374:                    if (hasConnection()) {
1375:                        return wrappedConnection.isOpen();
1376:                    } else {
1377:                        return false;
1378:                    }
1379:                }
1380:
1381:                public boolean closeIfStale() throws IOException {
1382:                    if (hasConnection()) {
1383:                        return wrappedConnection.closeIfStale();
1384:                    } else {
1385:                        return false;
1386:                    }
1387:                }
1388:
1389:                public boolean isProxied() {
1390:                    if (hasConnection()) {
1391:                        return wrappedConnection.isProxied();
1392:                    } else {
1393:                        return false;
1394:                    }
1395:                }
1396:
1397:                public boolean isResponseAvailable() throws IOException {
1398:                    if (hasConnection()) {
1399:                        return wrappedConnection.isResponseAvailable();
1400:                    } else {
1401:                        return false;
1402:                    }
1403:                }
1404:
1405:                public boolean isResponseAvailable(int timeout)
1406:                        throws IOException {
1407:                    if (hasConnection()) {
1408:                        return wrappedConnection.isResponseAvailable(timeout);
1409:                    } else {
1410:                        return false;
1411:                    }
1412:                }
1413:
1414:                public boolean isSecure() {
1415:                    if (hasConnection()) {
1416:                        return wrappedConnection.isSecure();
1417:                    } else {
1418:                        return false;
1419:                    }
1420:                }
1421:
1422:                public boolean isTransparent() {
1423:                    if (hasConnection()) {
1424:                        return wrappedConnection.isTransparent();
1425:                    } else {
1426:                        return false;
1427:                    }
1428:                }
1429:
1430:                public void open() throws IOException {
1431:                    if (hasConnection()) {
1432:                        wrappedConnection.open();
1433:                    } else {
1434:                        throw new IllegalStateException(
1435:                                "Connection has been released");
1436:                    }
1437:                }
1438:
1439:                /**
1440:                 * @deprecated
1441:                 */
1442:                public void print(String data) throws IOException,
1443:                        IllegalStateException {
1444:                    if (hasConnection()) {
1445:                        wrappedConnection.print(data);
1446:                    } else {
1447:                        throw new IllegalStateException(
1448:                                "Connection has been released");
1449:                    }
1450:                }
1451:
1452:                public void printLine() throws IOException,
1453:                        IllegalStateException {
1454:                    if (hasConnection()) {
1455:                        wrappedConnection.printLine();
1456:                    } else {
1457:                        throw new IllegalStateException(
1458:                                "Connection has been released");
1459:                    }
1460:                }
1461:
1462:                /**
1463:                 * @deprecated
1464:                 */
1465:                public void printLine(String data) throws IOException,
1466:                        IllegalStateException {
1467:                    if (hasConnection()) {
1468:                        wrappedConnection.printLine(data);
1469:                    } else {
1470:                        throw new IllegalStateException(
1471:                                "Connection has been released");
1472:                    }
1473:                }
1474:
1475:                /**
1476:                 * @deprecated
1477:                 */
1478:                public String readLine() throws IOException,
1479:                        IllegalStateException {
1480:                    if (hasConnection()) {
1481:                        return wrappedConnection.readLine();
1482:                    } else {
1483:                        throw new IllegalStateException(
1484:                                "Connection has been released");
1485:                    }
1486:                }
1487:
1488:                public String readLine(String charset) throws IOException,
1489:                        IllegalStateException {
1490:                    if (hasConnection()) {
1491:                        return wrappedConnection.readLine(charset);
1492:                    } else {
1493:                        throw new IllegalStateException(
1494:                                "Connection has been released");
1495:                    }
1496:                }
1497:
1498:                public void releaseConnection() {
1499:                    if (!isLocked() && hasConnection()) {
1500:                        HttpConnection wrappedConnection = this .wrappedConnection;
1501:                        this .wrappedConnection = null;
1502:                        wrappedConnection.releaseConnection();
1503:                    } else {
1504:                        // do nothing
1505:                    }
1506:                }
1507:
1508:                /**
1509:                 * @deprecated
1510:                 */
1511:                public void setConnectionTimeout(int timeout) {
1512:                    if (hasConnection()) {
1513:                        wrappedConnection.setConnectionTimeout(timeout);
1514:                    } else {
1515:                        // do nothing
1516:                    }
1517:                }
1518:
1519:                public void setHost(String host) throws IllegalStateException {
1520:                    if (hasConnection()) {
1521:                        wrappedConnection.setHost(host);
1522:                    } else {
1523:                        // do nothing
1524:                    }
1525:                }
1526:
1527:                public void setHttpConnectionManager(
1528:                        HttpConnectionManager httpConnectionManager) {
1529:                    if (hasConnection()) {
1530:                        wrappedConnection
1531:                                .setHttpConnectionManager(httpConnectionManager);
1532:                    } else {
1533:                        // do nothing
1534:                    }
1535:                }
1536:
1537:                public void setLastResponseInputStream(InputStream inStream) {
1538:                    if (hasConnection()) {
1539:                        wrappedConnection.setLastResponseInputStream(inStream);
1540:                    } else {
1541:                        // do nothing
1542:                    }
1543:                }
1544:
1545:                public void setPort(int port) throws IllegalStateException {
1546:                    if (hasConnection()) {
1547:                        wrappedConnection.setPort(port);
1548:                    } else {
1549:                        // do nothing
1550:                    }
1551:                }
1552:
1553:                public void setProtocol(Protocol protocol) {
1554:                    if (hasConnection()) {
1555:                        wrappedConnection.setProtocol(protocol);
1556:                    } else {
1557:                        // do nothing
1558:                    }
1559:                }
1560:
1561:                public void setProxyHost(String host)
1562:                        throws IllegalStateException {
1563:                    if (hasConnection()) {
1564:                        wrappedConnection.setProxyHost(host);
1565:                    } else {
1566:                        // do nothing
1567:                    }
1568:                }
1569:
1570:                public void setProxyPort(int port) throws IllegalStateException {
1571:                    if (hasConnection()) {
1572:                        wrappedConnection.setProxyPort(port);
1573:                    } else {
1574:                        // do nothing
1575:                    }
1576:                }
1577:
1578:                /**
1579:                 * @deprecated
1580:                 */
1581:                public void setSoTimeout(int timeout) throws SocketException,
1582:                        IllegalStateException {
1583:                    if (hasConnection()) {
1584:                        wrappedConnection.setSoTimeout(timeout);
1585:                    } else {
1586:                        // do nothing
1587:                    }
1588:                }
1589:
1590:                /**
1591:                 * @deprecated
1592:                 */
1593:                public void shutdownOutput() {
1594:                    if (hasConnection()) {
1595:                        wrappedConnection.shutdownOutput();
1596:                    } else {
1597:                        // do nothing
1598:                    }
1599:                }
1600:
1601:                public void tunnelCreated() throws IllegalStateException,
1602:                        IOException {
1603:                    if (hasConnection()) {
1604:                        wrappedConnection.tunnelCreated();
1605:                    } else {
1606:                        // do nothing
1607:                    }
1608:                }
1609:
1610:                public void write(byte[] data, int offset, int length)
1611:                        throws IOException, IllegalStateException {
1612:                    if (hasConnection()) {
1613:                        wrappedConnection.write(data, offset, length);
1614:                    } else {
1615:                        throw new IllegalStateException(
1616:                                "Connection has been released");
1617:                    }
1618:                }
1619:
1620:                public void write(byte[] data) throws IOException,
1621:                        IllegalStateException {
1622:                    if (hasConnection()) {
1623:                        wrappedConnection.write(data);
1624:                    } else {
1625:                        throw new IllegalStateException(
1626:                                "Connection has been released");
1627:                    }
1628:                }
1629:
1630:                public void writeLine() throws IOException,
1631:                        IllegalStateException {
1632:                    if (hasConnection()) {
1633:                        wrappedConnection.writeLine();
1634:                    } else {
1635:                        throw new IllegalStateException(
1636:                                "Connection has been released");
1637:                    }
1638:                }
1639:
1640:                public void writeLine(byte[] data) throws IOException,
1641:                        IllegalStateException {
1642:                    if (hasConnection()) {
1643:                        wrappedConnection.writeLine(data);
1644:                    } else {
1645:                        throw new IllegalStateException(
1646:                                "Connection has been released");
1647:                    }
1648:                }
1649:
1650:                public void flushRequestOutputStream() throws IOException {
1651:                    if (hasConnection()) {
1652:                        wrappedConnection.flushRequestOutputStream();
1653:                    } else {
1654:                        throw new IllegalStateException(
1655:                                "Connection has been released");
1656:                    }
1657:                }
1658:
1659:                /**
1660:                 * @deprecated
1661:                 */
1662:                public int getSoTimeout() throws SocketException {
1663:                    if (hasConnection()) {
1664:                        return wrappedConnection.getSoTimeout();
1665:                    } else {
1666:                        throw new IllegalStateException(
1667:                                "Connection has been released");
1668:                    }
1669:                }
1670:
1671:                /**
1672:                 * @deprecated
1673:                 */
1674:                public String getVirtualHost() {
1675:                    if (hasConnection()) {
1676:                        return wrappedConnection.getVirtualHost();
1677:                    } else {
1678:                        throw new IllegalStateException(
1679:                                "Connection has been released");
1680:                    }
1681:                }
1682:
1683:                /**
1684:                 * @deprecated
1685:                 */
1686:                public void setVirtualHost(String host)
1687:                        throws IllegalStateException {
1688:                    if (hasConnection()) {
1689:                        wrappedConnection.setVirtualHost(host);
1690:                    } else {
1691:                        throw new IllegalStateException(
1692:                                "Connection has been released");
1693:                    }
1694:                }
1695:
1696:                public int getSendBufferSize() throws SocketException {
1697:                    if (hasConnection()) {
1698:                        return wrappedConnection.getSendBufferSize();
1699:                    } else {
1700:                        throw new IllegalStateException(
1701:                                "Connection has been released");
1702:                    }
1703:                }
1704:
1705:                /**
1706:                 * @deprecated
1707:                 */
1708:                public void setSendBufferSize(int sendBufferSize)
1709:                        throws SocketException {
1710:                    if (hasConnection()) {
1711:                        wrappedConnection.setSendBufferSize(sendBufferSize);
1712:                    } else {
1713:                        throw new IllegalStateException(
1714:                                "Connection has been released");
1715:                    }
1716:                }
1717:
1718:                public HttpConnectionParams getParams() {
1719:                    if (hasConnection()) {
1720:                        return wrappedConnection.getParams();
1721:                    } else {
1722:                        throw new IllegalStateException(
1723:                                "Connection has been released");
1724:                    }
1725:                }
1726:
1727:                public void setParams(final HttpConnectionParams params) {
1728:                    if (hasConnection()) {
1729:                        wrappedConnection.setParams(params);
1730:                    } else {
1731:                        throw new IllegalStateException(
1732:                                "Connection has been released");
1733:                    }
1734:                }
1735:
1736:                /* (non-Javadoc)
1737:                 * @see org.apache.commons.httpclient.HttpConnection#print(java.lang.String, java.lang.String)
1738:                 */
1739:                public void print(String data, String charset)
1740:                        throws IOException, IllegalStateException {
1741:                    if (hasConnection()) {
1742:                        wrappedConnection.print(data, charset);
1743:                    } else {
1744:                        throw new IllegalStateException(
1745:                                "Connection has been released");
1746:                    }
1747:                }
1748:
1749:                /* (non-Javadoc)
1750:                 * @see org.apache.commons.httpclient.HttpConnection#printLine(java.lang.String, java.lang.String)
1751:                 */
1752:                public void printLine(String data, String charset)
1753:                        throws IOException, IllegalStateException {
1754:                    if (hasConnection()) {
1755:                        wrappedConnection.printLine(data, charset);
1756:                    } else {
1757:                        throw new IllegalStateException(
1758:                                "Connection has been released");
1759:                    }
1760:                }
1761:
1762:                /* (non-Javadoc)
1763:                 * @see org.apache.commons.httpclient.HttpConnection#setSocketTimeout(int)
1764:                 */
1765:                public void setSocketTimeout(int timeout)
1766:                        throws SocketException, IllegalStateException {
1767:                    if (hasConnection()) {
1768:                        wrappedConnection.setSocketTimeout(timeout);
1769:                    } else {
1770:                        throw new IllegalStateException(
1771:                                "Connection has been released");
1772:                    }
1773:                }
1774:
1775:            }
1776:
1777:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.