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}