1fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson/* 2fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one or more 3fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * contributor license agreements. See the NOTICE file distributed with 4fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * this work for additional information regarding copyright ownership. 5fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * The ASF licenses this file to You under the Apache License, Version 2.0 6fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * (the "License"); you may not use this file except in compliance with 7fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * the License. You may obtain a copy of the License at 8fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * 9fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 10fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * 11fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * Unless required by applicable law or agreed to in writing, software 12fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 13fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * See the License for the specific language governing permissions and 15fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * limitations under the License. 16fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson */ 17fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 18fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilsonpackage org.apache.harmony.luni.internal.net.www.protocol.http; 19fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 20fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilsonimport java.io.IOException; 21fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilsonimport java.util.ArrayList; 22fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilsonimport java.util.HashMap; 23fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilsonimport java.util.List; 24fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 25fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson/** 26fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * A pool of HTTP connections. This class exposes its tuning parameters as 27fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * system properties: 28fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * <ul> 29fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * <li>{@code http.keepAlive} true if HTTP connections should be pooled at 30fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * all. Default is true. 31fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * <li>{@code http.maxConnections} maximum number of connections to each URI. 32fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * Default is 5. 33fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * </ul> 34fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * 35fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * <p>This class <i>doesn't</i> adjust its configuration as system properties 36fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * are changed. This assumes that the applications that set these parameters do 37fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * so before making HTTP connections, and that this class is initialized lazily. 38fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * 39fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * <p>If a security manager is in place, HTTP connection pooling will be 40fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * disabled and these system properties will be ignored. 41fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson */ 42fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilsonpublic final class HttpConnectionPool { 43fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 44fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson public static final HttpConnectionPool INSTANCE = new HttpConnectionPool(); 45fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 46fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson private final int maxConnections; 47fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson private final HashMap<HttpConfiguration, List<HttpConnection>> connectionPool 48fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson = new HashMap<HttpConfiguration, List<HttpConnection>>(); 49fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 50fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson private HttpConnectionPool() { 51fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson SecurityManager security = System.getSecurityManager(); 52fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson if (security != null) { 53fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson maxConnections = 0; 54fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson return; 55fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 56fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 57fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson String keepAlive = System.getProperty("http.keepAlive"); 58fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson if (keepAlive != null && !Boolean.parseBoolean(keepAlive)) { 59fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson maxConnections = 0; 60fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson return; 61fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 62fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 63fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson String maxConnectionsString = System.getProperty("http.maxConnections"); 64fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson this.maxConnections = maxConnectionsString != null 65fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson ? Integer.parseInt(maxConnectionsString) 66fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson : 5; 67fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 68fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 69fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson public HttpConnection get(HttpConfiguration config, int connectTimeout) throws IOException { 70fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson // First try to reuse an existing HTTP connection. 71fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson synchronized (connectionPool) { 72fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson List<HttpConnection> connections = connectionPool.get(config); 73fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson if (connections != null) { 74fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson while (!connections.isEmpty()) { 75fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson HttpConnection connection = connections.remove(connections.size() - 1); 76fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson if (!connection.isStale()) { 77fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson return connection; 78fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 79fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 80fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson connectionPool.remove(config); 81fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 82fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 83fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 84fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson /* 85fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * We couldn't find a reusable connection, so we need to create a new 86fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson * connection. We're careful not to do so while holding a lock! 87fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson */ 88fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson return new HttpConnection(config, connectTimeout); 89fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 90fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 91fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson public void recycle(HttpConnection connection) { 92fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson if (maxConnections > 0 && connection.isEligibleForRecycling()) { 93fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson HttpConfiguration config = connection.getHttpConfiguration(); 94fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson synchronized (connectionPool) { 95fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson List<HttpConnection> connections = connectionPool.get(config); 96fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson if (connections == null) { 97fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson connections = new ArrayList<HttpConnection>(); 98fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson connectionPool.put(config, connections); 99fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 100fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson if (connections.size() < maxConnections) { 101fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson connections.add(connection); 102fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson return; // keep the connection open 103fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 104fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 105fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 106fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson 107fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson // don't close streams while holding a lock! 108fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson connection.closeSocketAndStreams(); 109fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson } 110fd1674c75d7b6500168137a2213877e45e49bbd2Jesse Wilson}