001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.harmony.luni.internal.net.www.protocol.http;
018:
019: import java.io.IOException;
020: import java.net.Proxy;
021: import java.net.URI;
022: import java.security.AccessController;
023: import java.util.ArrayList;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028:
029: import org.apache.harmony.luni.util.PriviAction;
030:
031: /**
032: * <code>HttpConnectionManager</code> manages a pool of <code>HttpConnection</code>s
033: * that are not currently in use and is used to get hold of persistent <code>HttpConnection</code>s.
034: * Clients should return an <code>HttpConnection</code> to the pool after use by calling
035: * <code>returnConnectionToPool</code>
036: *
037: * Two system properties affect the behaviour of this class - <code>http.maxConnections</code>
038: * and <code>http.keepAlive</code>. <code>http.keepAlive</code> determines whether
039: * or not connections should be persisted and <code>http.maxConnections</code>
040: * determines the maximum number of connections to each individual host that
041: * should be kept in the pool.
042: */
043: public class HttpConnectionManager {
044:
045: // The maximum number of connections to any location
046: private static int maxConnections = 5;
047:
048: // Keeps connections alive if true
049: private static boolean keepAlive = true;
050:
051: private static HttpConnectionManager defaultConnectionManager;
052: private ConnectionPool pool = new ConnectionPool();
053:
054: /**
055: * Returns the default connection manager
056: */
057: public static HttpConnectionManager getDefault() {
058: if (defaultConnectionManager == null) {
059: defaultConnectionManager = new HttpConnectionManager();
060: }
061: return defaultConnectionManager;
062: }
063:
064: public HttpConnection getConnection(URI uri, int connectTimeout)
065: throws IOException {
066: checkSystemProperties();
067: HttpConfiguration config = new HttpConfiguration(uri);
068: return pool.getHttpConnection(config, connectTimeout);
069: }
070:
071: public HttpConnection getConnection(URI uri, Proxy proxy,
072: int connectTimeout) throws IOException {
073: checkSystemProperties();
074: HttpConfiguration config = new HttpConfiguration(uri, proxy);
075: return pool.getHttpConnection(config, connectTimeout);
076: }
077:
078: public void returnConnectionToPool(HttpConnection connection) {
079: checkSystemProperties();
080: pool.returnConnection(connection);
081: }
082:
083: public int numFreeConnections() {
084: return pool.numFreeConnections();
085: }
086:
087: private void checkSystemProperties() {
088: String httpMaxConnections = AccessController
089: .doPrivileged(new PriviAction<String>(
090: "http.maxConnections"));
091: String httpKeepAlive = AccessController
092: .doPrivileged(new PriviAction<String>("http.keepAlive"));
093: if (httpMaxConnections != null) {
094: maxConnections = Integer.parseInt(httpMaxConnections);
095: }
096: if (httpKeepAlive != null) {
097: keepAlive = Boolean.parseBoolean(httpKeepAlive);
098: if (!keepAlive) {
099: pool.clear();
100: }
101: }
102: }
103:
104: private static class ConnectionPool {
105:
106: private Map<HttpConfiguration, List<HttpConnection>> freeConnectionMap = new HashMap<HttpConfiguration, List<HttpConnection>>(); // Map of free Sockets
107:
108: public synchronized void clear() {
109: for (Iterator<List<HttpConnection>> iter = freeConnectionMap
110: .values().iterator(); iter.hasNext();) {
111: List<HttpConnection> connections = iter.next();
112: for (Iterator<HttpConnection> iterator = connections
113: .iterator(); iterator.hasNext();) {
114: HttpConnection connection = iterator.next();
115: connection.closeSocketAndStreams();
116: }
117: }
118: freeConnectionMap.clear();
119: }
120:
121: public synchronized void returnConnection(
122: HttpConnection connection) {
123: if (!connection.getSocket().isClosed() && keepAlive) {
124: HttpConfiguration config = connection
125: .getHttpConfiguration();
126: List<HttpConnection> connections = freeConnectionMap
127: .get(config);
128: if (connections == null) {
129: connections = new ArrayList<HttpConnection>();
130: freeConnectionMap.put(config, connections);
131: }
132: if (connections.size() < HttpConnectionManager.maxConnections) {
133: if (!connections.contains(connection)) {
134: connections.add(connection);
135: }
136: } else {
137: connection.closeSocketAndStreams();
138: }
139: } else {
140: // Make sure all streams are closed etc.
141: connection.closeSocketAndStreams();
142: }
143: }
144:
145: public synchronized HttpConnection getHttpConnection(
146: HttpConfiguration config, int connectTimeout)
147: throws IOException {
148: List<HttpConnection> connections = freeConnectionMap
149: .get(config);
150: if (keepAlive && connections == null) {
151: connections = new ArrayList<HttpConnection>();
152: freeConnectionMap.put(config, connections);
153: }
154: if (!keepAlive || connections.isEmpty()) {
155: HttpConnection connection = new HttpConnection(config,
156: connectTimeout);
157: return connection;
158: } else {
159: HttpConnection connection = connections.get(0);
160: connections.remove(0);
161: if (!connection.isStale()) {
162: SecurityManager security = System
163: .getSecurityManager();
164: if (security != null) {
165: security.checkConnect(connection.getSocket()
166: .getInetAddress().getHostName(),
167: connection.getSocket().getPort());
168: }
169: return connection;
170: } else {
171: return getHttpConnection(config, connectTimeout);
172: }
173: }
174: }
175:
176: public int numFreeConnections() {
177: int numFree = 0;
178: for (Iterator<List<HttpConnection>> iter = freeConnectionMap
179: .values().iterator(); iter.hasNext();) {
180: List<HttpConnection> connections = iter.next();
181: numFree += connections.size();
182: }
183: return numFree;
184: }
185: }
186:
187: public void reset() {
188: pool.clear();
189: }
190:
191: }
|