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.Contract;
38 import org.apache.http.annotation.ThreadingBehavior;
39 import org.apache.http.conn.ClientConnectionManager;
40 import org.apache.http.conn.ClientConnectionOperator;
41 import org.apache.http.conn.ClientConnectionRequest;
42 import org.apache.http.conn.ConnectionPoolTimeoutException;
43 import org.apache.http.conn.DnsResolver;
44 import org.apache.http.conn.ManagedClientConnection;
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 @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
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 timeUnit) {
102 this(schemeRegistry, timeToLive, timeUnit, new SystemDefaultDnsResolver());
103 }
104
105 public PoolingClientConnectionManager(final SchemeRegistry schemeRegistry,
106 final long timeToLive, final TimeUnit timeUnit,
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, timeUnit);
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 @Override
143 public SchemeRegistry getSchemeRegistry() {
144 return this.schemeRegistry;
145 }
146
147 private String format(final HttpRoute route, final Object state) {
148 final StringBuilder buf = new StringBuilder();
149 buf.append("[route: ").append(route).append("]");
150 if (state != null) {
151 buf.append("[state: ").append(state).append("]");
152 }
153 return buf.toString();
154 }
155
156 private String formatStats(final HttpRoute route) {
157 final StringBuilder buf = new StringBuilder();
158 final PoolStats totals = this.pool.getTotalStats();
159 final PoolStats stats = this.pool.getStats(route);
160 buf.append("[total kept alive: ").append(totals.getAvailable()).append("; ");
161 buf.append("route allocated: ").append(stats.getLeased() + stats.getAvailable());
162 buf.append(" of ").append(stats.getMax()).append("; ");
163 buf.append("total allocated: ").append(totals.getLeased() + totals.getAvailable());
164 buf.append(" of ").append(totals.getMax()).append("]");
165 return buf.toString();
166 }
167
168 private String format(final HttpPoolEntry entry) {
169 final StringBuilder buf = new StringBuilder();
170 buf.append("[id: ").append(entry.getId()).append("]");
171 buf.append("[route: ").append(entry.getRoute()).append("]");
172 final Object state = entry.getState();
173 if (state != null) {
174 buf.append("[state: ").append(state).append("]");
175 }
176 return buf.toString();
177 }
178
179 @Override
180 public ClientConnectionRequest requestConnection(
181 final HttpRoute route,
182 final Object state) {
183 Args.notNull(route, "HTTP route");
184 if (this.log.isDebugEnabled()) {
185 this.log.debug("Connection request: " + format(route, state) + formatStats(route));
186 }
187 final Future<HttpPoolEntry> future = this.pool.lease(route, state);
188
189 return new ClientConnectionRequest() {
190
191 @Override
192 public void abortRequest() {
193 future.cancel(true);
194 }
195
196 @Override
197 public ManagedClientConnection getConnection(
198 final long timeout,
199 final TimeUnit timeUnit) throws InterruptedException, ConnectionPoolTimeoutException {
200 return leaseConnection(future, timeout, timeUnit);
201 }
202
203 };
204
205 }
206
207 ManagedClientConnection leaseConnection(
208 final Future<HttpPoolEntry> future,
209 final long timeout,
210 final TimeUnit timeUnit) throws InterruptedException, ConnectionPoolTimeoutException {
211 final HttpPoolEntry entry;
212 try {
213 entry = future.get(timeout, timeUnit);
214 if (entry == null || future.isCancelled()) {
215 throw new InterruptedException();
216 }
217 Asserts.check(entry.getConnection() != null, "Pool entry with no connection");
218 if (this.log.isDebugEnabled()) {
219 this.log.debug("Connection leased: " + format(entry) + formatStats(entry.getRoute()));
220 }
221 return new ManagedClientConnectionImpl(this, this.operator, entry);
222 } catch (final ExecutionException ex) {
223 Throwable cause = ex.getCause();
224 if (cause == null) {
225 cause = ex;
226 }
227 this.log.error("Unexpected exception leasing connection from pool", cause);
228
229 throw new InterruptedException();
230 } catch (final TimeoutException ex) {
231 throw new ConnectionPoolTimeoutException("Timeout waiting for connection from pool");
232 }
233 }
234
235 @Override
236 public void releaseConnection(
237 final ManagedClientConnection conn, final long keepalive, final TimeUnit timeUnit) {
238
239 Args.check(conn instanceof ManagedClientConnectionImpl, "Connection class mismatch, " +
240 "connection not obtained from this manager");
241 final ManagedClientConnectionImplhttp/impl/conn/ManagedClientConnectionImpl.html#ManagedClientConnectionImpl">ManagedClientConnectionImpl managedConn = (ManagedClientConnectionImpl) conn;
242 Asserts.check(managedConn.getManager() == this, "Connection not obtained from this manager");
243 synchronized (managedConn) {
244 final HttpPoolEntry entry = managedConn.detach();
245 if (entry == null) {
246 return;
247 }
248 try {
249 if (managedConn.isOpen() && !managedConn.isMarkedReusable()) {
250 try {
251 managedConn.shutdown();
252 } catch (final IOException iox) {
253 if (this.log.isDebugEnabled()) {
254 this.log.debug("I/O exception shutting down released connection", iox);
255 }
256 }
257 }
258
259 if (managedConn.isMarkedReusable()) {
260 entry.updateExpiry(keepalive, timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS);
261 if (this.log.isDebugEnabled()) {
262 final String s;
263 if (keepalive > 0) {
264 s = "for " + keepalive + " " + timeUnit;
265 } else {
266 s = "indefinitely";
267 }
268 this.log.debug("Connection " + format(entry) + " can be kept alive " + s);
269 }
270 }
271 } finally {
272 this.pool.release(entry, managedConn.isMarkedReusable());
273 }
274 if (this.log.isDebugEnabled()) {
275 this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute()));
276 }
277 }
278 }
279
280 @Override
281 public void shutdown() {
282 this.log.debug("Connection manager is shutting down");
283 try {
284 this.pool.shutdown();
285 } catch (final IOException ex) {
286 this.log.debug("I/O exception shutting down connection manager", ex);
287 }
288 this.log.debug("Connection manager shut down");
289 }
290
291 @Override
292 public void closeIdleConnections(final long idleTimeout, final TimeUnit timeUnit) {
293 if (this.log.isDebugEnabled()) {
294 this.log.debug("Closing connections idle longer than " + idleTimeout + " " + timeUnit);
295 }
296 this.pool.closeIdle(idleTimeout, timeUnit);
297 }
298
299 @Override
300 public void closeExpiredConnections() {
301 this.log.debug("Closing expired connections");
302 this.pool.closeExpired();
303 }
304
305 @Override
306 public int getMaxTotal() {
307 return this.pool.getMaxTotal();
308 }
309
310 @Override
311 public void setMaxTotal(final int max) {
312 this.pool.setMaxTotal(max);
313 }
314
315 @Override
316 public int getDefaultMaxPerRoute() {
317 return this.pool.getDefaultMaxPerRoute();
318 }
319
320 @Override
321 public void setDefaultMaxPerRoute(final int max) {
322 this.pool.setDefaultMaxPerRoute(max);
323 }
324
325 @Override
326 public int getMaxPerRoute(final HttpRoute route) {
327 return this.pool.getMaxPerRoute(route);
328 }
329
330 @Override
331 public void setMaxPerRoute(final HttpRoute route, final int max) {
332 this.pool.setMaxPerRoute(route, max);
333 }
334
335 @Override
336 public PoolStats getTotalStats() {
337 return this.pool.getTotalStats();
338 }
339
340 @Override
341 public PoolStats getStats(final HttpRoute route) {
342 return this.pool.getStats(route);
343 }
344
345 }
346