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
28 package org.apache.http.impl.conn;
29
30 import java.io.IOException;
31 import java.util.concurrent.TimeUnit;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.http.annotation.GuardedBy;
36 import org.apache.http.annotation.ThreadSafe;
37 import org.apache.http.conn.ClientConnectionManager;
38 import org.apache.http.conn.ClientConnectionOperator;
39 import org.apache.http.conn.ClientConnectionRequest;
40 import org.apache.http.conn.ManagedClientConnection;
41 import org.apache.http.conn.routing.HttpRoute;
42 import org.apache.http.conn.routing.RouteTracker;
43 import org.apache.http.conn.scheme.SchemeRegistry;
44 import org.apache.http.params.HttpParams;
45 import org.apache.http.util.Args;
46 import org.apache.http.util.Asserts;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 @ThreadSafe
65 @Deprecated
66 public class SingleClientConnManager implements ClientConnectionManager {
67
68 private final Log log = LogFactory.getLog(getClass());
69
70
71 public final static String MISUSE_MESSAGE =
72 "Invalid use of SingleClientConnManager: connection still allocated.\n" +
73 "Make sure to release the connection before allocating another one.";
74
75
76 protected final SchemeRegistry schemeRegistry;
77
78
79 protected final ClientConnectionOperator connOperator;
80
81
82 protected final boolean alwaysShutDown;
83
84
85 @GuardedBy("this")
86 protected volatile PoolEntry uniquePoolEntry;
87
88
89 @GuardedBy("this")
90 protected volatile ConnAdapter managedConn;
91
92
93 @GuardedBy("this")
94 protected volatile long lastReleaseTime;
95
96
97 @GuardedBy("this")
98 protected volatile long connectionExpiresTime;
99
100
101 protected volatile boolean isShutDown;
102
103
104
105
106
107
108
109
110
111 @Deprecated
112 public SingleClientConnManager(final HttpParams params,
113 final SchemeRegistry schreg) {
114 this(schreg);
115 }
116
117
118
119
120
121 public SingleClientConnManager(final SchemeRegistry schreg) {
122 Args.notNull(schreg, "Scheme registry");
123 this.schemeRegistry = schreg;
124 this.connOperator = createConnectionOperator(schreg);
125 this.uniquePoolEntry = new PoolEntry();
126 this.managedConn = null;
127 this.lastReleaseTime = -1L;
128 this.alwaysShutDown = false;
129 this.isShutDown = false;
130 }
131
132
133
134
135 public SingleClientConnManager() {
136 this(SchemeRegistryFactory.createDefault());
137 }
138
139 @Override
140 protected void finalize() throws Throwable {
141 try {
142 shutdown();
143 } finally {
144 super.finalize();
145 }
146 }
147
148 public SchemeRegistry getSchemeRegistry() {
149 return this.schemeRegistry;
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164 protected ClientConnectionOperator
165 createConnectionOperator(final SchemeRegistry schreg) {
166 return new DefaultClientConnectionOperator(schreg);
167 }
168
169
170
171
172
173
174 protected final void assertStillUp() throws IllegalStateException {
175 Asserts.check(!this.isShutDown, "Manager is shut down");
176 }
177
178 public final ClientConnectionRequest requestConnection(
179 final HttpRoute route,
180 final Object state) {
181
182 return new ClientConnectionRequest() {
183
184 public void abortRequest() {
185
186 }
187
188 public ManagedClientConnection getConnection(
189 final long timeout, final TimeUnit tunit) {
190 return SingleClientConnManager.this.getConnection(
191 route, state);
192 }
193
194 };
195 }
196
197
198
199
200
201
202
203
204
205 public ManagedClientConnection getConnection(final HttpRoute route, final Object state) {
206 Args.notNull(route, "Route");
207 assertStillUp();
208
209 if (log.isDebugEnabled()) {
210 log.debug("Get connection for route " + route);
211 }
212
213 synchronized (this) {
214
215 Asserts.check(managedConn == null, MISUSE_MESSAGE);
216
217
218 boolean recreate = false;
219 boolean shutdown = false;
220
221
222 closeExpiredConnections();
223
224 if (uniquePoolEntry.connection.isOpen()) {
225 final RouteTracker tracker = uniquePoolEntry.tracker;
226 shutdown = (tracker == null ||
227 !tracker.toRoute().equals(route));
228 } else {
229
230
231
232
233
234 recreate = true;
235 }
236
237 if (shutdown) {
238 recreate = true;
239 try {
240 uniquePoolEntry.shutdown();
241 } catch (final IOException iox) {
242 log.debug("Problem shutting down connection.", iox);
243 }
244 }
245
246 if (recreate) {
247 uniquePoolEntry = new PoolEntry();
248 }
249
250 managedConn = new ConnAdapter(uniquePoolEntry, route);
251
252 return managedConn;
253 }
254 }
255
256 public void releaseConnection(
257 final ManagedClientConnection conn,
258 final long validDuration, final TimeUnit timeUnit) {
259 Args.check(conn instanceof ConnAdapter, "Connection class mismatch, " +
260 "connection not obtained from this manager");
261 assertStillUp();
262
263 if (log.isDebugEnabled()) {
264 log.debug("Releasing connection " + conn);
265 }
266
267 final ConnAdapter sca = (ConnAdapter) conn;
268 synchronized (sca) {
269 if (sca.poolEntry == null)
270 {
271 return;
272 }
273 final ClientConnectionManager manager = sca.getManager();
274 Asserts.check(manager == this, "Connection not obtained from this manager");
275 try {
276
277 if (sca.isOpen() && (this.alwaysShutDown ||
278 !sca.isMarkedReusable())
279 ) {
280 if (log.isDebugEnabled()) {
281 log.debug
282 ("Released connection open but not reusable.");
283 }
284
285
286
287
288 sca.shutdown();
289 }
290 } catch (final IOException iox) {
291 if (log.isDebugEnabled()) {
292 log.debug("Exception shutting down released connection.",
293 iox);
294 }
295 } finally {
296 sca.detach();
297 synchronized (this) {
298 managedConn = null;
299 lastReleaseTime = System.currentTimeMillis();
300 if(validDuration > 0) {
301 connectionExpiresTime = timeUnit.toMillis(validDuration) + lastReleaseTime;
302 } else {
303 connectionExpiresTime = Long.MAX_VALUE;
304 }
305 }
306 }
307 }
308 }
309
310 public void closeExpiredConnections() {
311 final long time = connectionExpiresTime;
312 if (System.currentTimeMillis() >= time) {
313 closeIdleConnections(0, TimeUnit.MILLISECONDS);
314 }
315 }
316
317 public void closeIdleConnections(final long idletime, final TimeUnit tunit) {
318 assertStillUp();
319
320
321 Args.notNull(tunit, "Time unit");
322
323 synchronized (this) {
324 if ((managedConn == null) && uniquePoolEntry.connection.isOpen()) {
325 final long cutoff =
326 System.currentTimeMillis() - tunit.toMillis(idletime);
327 if (lastReleaseTime <= cutoff) {
328 try {
329 uniquePoolEntry.close();
330 } catch (final IOException iox) {
331
332 log.debug("Problem closing idle connection.", iox);
333 }
334 }
335 }
336 }
337 }
338
339 public void shutdown() {
340 this.isShutDown = true;
341 synchronized (this) {
342 try {
343 if (uniquePoolEntry != null) {
344 uniquePoolEntry.shutdown();
345 }
346 } catch (final IOException iox) {
347
348 log.debug("Problem while shutting down manager.", iox);
349 } finally {
350 uniquePoolEntry = null;
351 managedConn = null;
352 }
353 }
354 }
355
356 protected void revokeConnection() {
357 final ConnAdapter conn = managedConn;
358 if (conn == null) {
359 return;
360 }
361 conn.detach();
362
363 synchronized (this) {
364 try {
365 uniquePoolEntry.shutdown();
366 } catch (final IOException iox) {
367
368 log.debug("Problem while shutting down connection.", iox);
369 }
370 }
371 }
372
373
374
375
376 protected class PoolEntry extends AbstractPoolEntry {
377
378
379
380
381
382 protected PoolEntry() {
383 super(SingleClientConnManager.this.connOperator, null);
384 }
385
386
387
388
389 protected void close() throws IOException {
390 shutdownEntry();
391 if (connection.isOpen()) {
392 connection.close();
393 }
394 }
395
396
397
398
399 protected void shutdown() throws IOException {
400 shutdownEntry();
401 if (connection.isOpen()) {
402 connection.shutdown();
403 }
404 }
405
406 }
407
408
409
410
411 protected class ConnAdapter extends AbstractPooledConnAdapter {
412
413
414
415
416
417
418
419 protected ConnAdapter(final PoolEntry entry, final HttpRoute route) {
420 super(SingleClientConnManager.this, entry);
421 markReusable();
422 entry.route = route;
423 }
424
425 }
426
427 }