1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.http.impl.conn;
28
29 import java.io.IOException;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.Future;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.TimeoutException;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.http.annotation.ThreadSafe;
38 import org.apache.http.conn.ClientConnectionManager;
39 import org.apache.http.conn.ClientConnectionOperator;
40 import org.apache.http.conn.ClientConnectionRequest;
41 import org.apache.http.conn.ConnectionPoolTimeoutException;
42 import org.apache.http.conn.DnsResolver;
43 import org.apache.http.conn.ManagedClientConnection;
44 import org.apache.http.conn.OperatedClientConnection;
45 import org.apache.http.conn.routing.HttpRoute;
46 import org.apache.http.conn.scheme.SchemeRegistry;
47 import org.apache.http.pool.ConnPoolControl;
48 import org.apache.http.pool.PoolStats;
49 import org.apache.http.util.Args;
50 import org.apache.http.util.Asserts;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 @Deprecated
73 @ThreadSafe
74 public class PoolingClientConnectionManager implements ClientConnectionManager, ConnPoolControl<HttpRoute> {
75
76 private final Log log = LogFactory.getLog(getClass());
77
78 private final SchemeRegistry schemeRegistry;
79
80 private final HttpConnPool pool;
81
82 private final ClientConnectionOperator operator;
83
84
85 private final DnsResolver dnsResolver;
86
87 public PoolingClientConnectionManager(final SchemeRegistry schreg) {
88 this(schreg, -1, TimeUnit.MILLISECONDS);
89 }
90
91 public PoolingClientConnectionManager(final SchemeRegistry schreg,final DnsResolver dnsResolver) {
92 this(schreg, -1, TimeUnit.MILLISECONDS,dnsResolver);
93 }
94
95 public PoolingClientConnectionManager() {
96 this(SchemeRegistryFactory.createDefault());
97 }
98
99 public PoolingClientConnectionManager(
100 final SchemeRegistry schemeRegistry,
101 final long timeToLive, final TimeUnit tunit) {
102 this(schemeRegistry, timeToLive, tunit, new SystemDefaultDnsResolver());
103 }
104
105 public PoolingClientConnectionManager(final SchemeRegistry schemeRegistry,
106 final long timeToLive, final TimeUnit tunit,
107 final DnsResolver dnsResolver) {
108 super();
109 Args.notNull(schemeRegistry, "Scheme registry");
110 Args.notNull(dnsResolver, "DNS resolver");
111 this.schemeRegistry = schemeRegistry;
112 this.dnsResolver = dnsResolver;
113 this.operator = createConnectionOperator(schemeRegistry);
114 this.pool = new HttpConnPool(this.log, this.operator, 2, 20, timeToLive, tunit);
115 }
116
117 @Override
118 protected void finalize() throws Throwable {
119 try {
120 shutdown();
121 } finally {
122 super.finalize();
123 }
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138 protected ClientConnectionOperator createConnectionOperator(final SchemeRegistry schreg) {
139 return new DefaultClientConnectionOperator(schreg, this.dnsResolver);
140 }
141
142 public SchemeRegistry getSchemeRegistry() {
143 return this.schemeRegistry;
144 }
145
146 private String format(final HttpRoute route, final Object state) {
147 final StringBuilder buf = new StringBuilder();
148 buf.append("[route: ").append(route).append("]");
149 if (state != null) {
150 buf.append("[state: ").append(state).append("]");
151 }
152 return buf.toString();
153 }
154
155 private String formatStats(final HttpRoute route) {
156 final StringBuilder buf = new StringBuilder();
157 final PoolStats totals = this.pool.getTotalStats();
158 final PoolStats stats = this.pool.getStats(route);
159 buf.append("[total kept alive: ").append(totals.getAvailable()).append("; ");
160 buf.append("route allocated: ").append(stats.getLeased() + stats.getAvailable());
161 buf.append(" of ").append(stats.getMax()).append("; ");
162 buf.append("total allocated: ").append(totals.getLeased() + totals.getAvailable());
163 buf.append(" of ").append(totals.getMax()).append("]");
164 return buf.toString();
165 }
166
167 private String format(final HttpPoolEntry entry) {
168 final StringBuilder buf = new StringBuilder();
169 buf.append("[id: ").append(entry.getId()).append("]");
170 buf.append("[route: ").append(entry.getRoute()).append("]");
171 final Object state = entry.getState();
172 if (state != null) {
173 buf.append("[state: ").append(state).append("]");
174 }
175 return buf.toString();
176 }
177
178 public ClientConnectionRequest requestConnection(
179 final HttpRoute route,
180 final Object state) {
181 Args.notNull(route, "HTTP route");
182 if (this.log.isDebugEnabled()) {
183 this.log.debug("Connection request: " + format(route, state) + formatStats(route));
184 }
185 final Future<HttpPoolEntry> future = this.pool.lease(route, state);
186
187 return new ClientConnectionRequest() {
188
189 public void abortRequest() {
190 future.cancel(true);
191 }
192
193 public ManagedClientConnection getConnection(
194 final long timeout,
195 final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
196 return leaseConnection(future, timeout, tunit);
197 }
198
199 };
200
201 }
202
203 ManagedClientConnection leaseConnection(
204 final Future<HttpPoolEntry> future,
205 final long timeout,
206 final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
207 HttpPoolEntry entry;
208 try {
209 entry = future.get(timeout, tunit);
210 if (entry == null || future.isCancelled()) {
211 throw new InterruptedException();
212 }
213 Asserts.check(entry.getConnection() != null, "Pool entry with no connection");
214 if (this.log.isDebugEnabled()) {
215 this.log.debug("Connection leased: " + format(entry) + formatStats(entry.getRoute()));
216 }
217 return new ManagedClientConnectionImpl(this, this.operator, entry);
218 } catch (final ExecutionException ex) {
219 Throwable cause = ex.getCause();
220 if (cause == null) {
221 cause = ex;
222 }
223 this.log.error("Unexpected exception leasing connection from pool", cause);
224
225 throw new InterruptedException();
226 } catch (final TimeoutException ex) {
227 throw new ConnectionPoolTimeoutException("Timeout waiting for connection from pool");
228 }
229 }
230
231 public void releaseConnection(
232 final ManagedClientConnection conn, final long keepalive, final TimeUnit tunit) {
233
234 Args.check(conn instanceof ManagedClientConnectionImpl, "Connection class mismatch, " +
235 "connection not obtained from this manager");
236 final ManagedClientConnectionImpl managedConn = (ManagedClientConnectionImpl) conn;
237 Asserts.check(managedConn.getManager() == this, "Connection not obtained from this manager");
238 synchronized (managedConn) {
239 final HttpPoolEntry entry = managedConn.detach();
240 if (entry == null) {
241 return;
242 }
243 try {
244 if (managedConn.isOpen() && !managedConn.isMarkedReusable()) {
245 try {
246 managedConn.shutdown();
247 } catch (final IOException iox) {
248 if (this.log.isDebugEnabled()) {
249 this.log.debug("I/O exception shutting down released connection", iox);
250 }
251 }
252 }
253
254 if (managedConn.isMarkedReusable()) {
255 entry.updateExpiry(keepalive, tunit != null ? tunit : TimeUnit.MILLISECONDS);
256 if (this.log.isDebugEnabled()) {
257 String s;
258 if (keepalive > 0) {
259 s = "for " + keepalive + " " + tunit;
260 } else {
261 s = "indefinitely";
262 }
263 this.log.debug("Connection " + format(entry) + " can be kept alive " + s);
264 }
265 }
266 } finally {
267 this.pool.release(entry, managedConn.isMarkedReusable());
268 }
269 if (this.log.isDebugEnabled()) {
270 this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute()));
271 }
272 }
273 }
274
275 public void shutdown() {
276 this.log.debug("Connection manager is shutting down");
277 try {
278 this.pool.shutdown();
279 } catch (final IOException ex) {
280 this.log.debug("I/O exception shutting down connection manager", ex);
281 }
282 this.log.debug("Connection manager shut down");
283 }
284
285 public void closeIdleConnections(final long idleTimeout, final TimeUnit tunit) {
286 if (this.log.isDebugEnabled()) {
287 this.log.debug("Closing connections idle longer than " + idleTimeout + " " + tunit);
288 }
289 this.pool.closeIdle(idleTimeout, tunit);
290 }
291
292 public void closeExpiredConnections() {
293 this.log.debug("Closing expired connections");
294 this.pool.closeExpired();
295 }
296
297 public int getMaxTotal() {
298 return this.pool.getMaxTotal();
299 }
300
301 public void setMaxTotal(final int max) {
302 this.pool.setMaxTotal(max);
303 }
304
305 public int getDefaultMaxPerRoute() {
306 return this.pool.getDefaultMaxPerRoute();
307 }
308
309 public void setDefaultMaxPerRoute(final int max) {
310 this.pool.setDefaultMaxPerRoute(max);
311 }
312
313 public int getMaxPerRoute(final HttpRoute route) {
314 return this.pool.getMaxPerRoute(route);
315 }
316
317 public void setMaxPerRoute(final HttpRoute route, final int max) {
318 this.pool.setMaxPerRoute(route, max);
319 }
320
321 public PoolStats getTotalStats() {
322 return this.pool.getTotalStats();
323 }
324
325 public PoolStats getStats(final HttpRoute route) {
326 return this.pool.getStats(route);
327 }
328
329 }
330