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.Contract;
36 import org.apache.http.annotation.ThreadingBehavior;
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 @Contract(threading = ThreadingBehavior.SAFE)
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 protected volatile PoolEntry uniquePoolEntry;
86
87
88 protected volatile ConnAdapter managedConn;
89
90
91 protected volatile long lastReleaseTime;
92
93
94 protected volatile long connectionExpiresTime;
95
96
97 protected volatile boolean isShutDown;
98
99
100
101
102
103
104
105
106
107 @Deprecated
108 public SingleClientConnManager(final HttpParams params,
109 final SchemeRegistry schreg) {
110 this(schreg);
111 }
112
113
114
115
116
117 public SingleClientConnManager(final SchemeRegistry schreg) {
118 Args.notNull(schreg, "Scheme registry");
119 this.schemeRegistry = schreg;
120 this.connOperator = createConnectionOperator(schreg);
121 this.uniquePoolEntry = new PoolEntry();
122 this.managedConn = null;
123 this.lastReleaseTime = -1L;
124 this.alwaysShutDown = false;
125 this.isShutDown = false;
126 }
127
128
129
130
131 public SingleClientConnManager() {
132 this(SchemeRegistryFactory.createDefault());
133 }
134
135 @Override
136 protected void finalize() throws Throwable {
137 try {
138 shutdown();
139 } finally {
140 super.finalize();
141 }
142 }
143
144 @Override
145 public SchemeRegistry getSchemeRegistry() {
146 return this.schemeRegistry;
147 }
148
149
150
151
152
153
154
155
156
157
158
159
160
161 protected ClientConnectionOperator
162 createConnectionOperator(final SchemeRegistry schreg) {
163 return new DefaultClientConnectionOperator(schreg);
164 }
165
166
167
168
169
170
171 protected final void assertStillUp() throws IllegalStateException {
172 Asserts.check(!this.isShutDown, "Manager is shut down");
173 }
174
175 @Override
176 public final ClientConnectionRequest requestConnection(
177 final HttpRoute route,
178 final Object state) {
179
180 return new ClientConnectionRequest() {
181
182 @Override
183 public void abortRequest() {
184
185 }
186
187 @Override
188 public ManagedClientConnection getConnection(
189 final long timeout, final TimeUnit timeUnit) {
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 @Override
257 public void releaseConnection(
258 final ManagedClientConnection conn,
259 final long validDuration, final TimeUnit timeUnit) {
260 Args.check(conn instanceof ConnAdapter, "Connection class mismatch, " +
261 "connection not obtained from this manager");
262 assertStillUp();
263
264 if (log.isDebugEnabled()) {
265 log.debug("Releasing connection " + conn);
266 }
267
268 final ConnAdapter sca = (ConnAdapter) conn;
269 synchronized (sca) {
270 if (sca.poolEntry == null)
271 {
272 return;
273 }
274 final ClientConnectionManager manager = sca.getManager();
275 Asserts.check(manager == this, "Connection not obtained from this manager");
276 try {
277
278 if (sca.isOpen() && (this.alwaysShutDown ||
279 !sca.isMarkedReusable())
280 ) {
281 if (log.isDebugEnabled()) {
282 log.debug
283 ("Released connection open but not reusable.");
284 }
285
286
287
288
289 sca.shutdown();
290 }
291 } catch (final IOException iox) {
292 if (log.isDebugEnabled()) {
293 log.debug("Exception shutting down released connection.",
294 iox);
295 }
296 } finally {
297 sca.detach();
298 synchronized (this) {
299 managedConn = null;
300 lastReleaseTime = System.currentTimeMillis();
301 if(validDuration > 0) {
302 connectionExpiresTime = timeUnit.toMillis(validDuration) + lastReleaseTime;
303 } else {
304 connectionExpiresTime = Long.MAX_VALUE;
305 }
306 }
307 }
308 }
309 }
310
311 @Override
312 public void closeExpiredConnections() {
313 final long time = connectionExpiresTime;
314 if (System.currentTimeMillis() >= time) {
315 closeIdleConnections(0, TimeUnit.MILLISECONDS);
316 }
317 }
318
319 @Override
320 public void closeIdleConnections(final long idletime, final TimeUnit timeUnit) {
321 assertStillUp();
322
323
324 Args.notNull(timeUnit, "Time unit");
325
326 synchronized (this) {
327 if ((managedConn == null) && uniquePoolEntry.connection.isOpen()) {
328 final long cutoff =
329 System.currentTimeMillis() - timeUnit.toMillis(idletime);
330 if (lastReleaseTime <= cutoff) {
331 try {
332 uniquePoolEntry.close();
333 } catch (final IOException iox) {
334
335 log.debug("Problem closing idle connection.", iox);
336 }
337 }
338 }
339 }
340 }
341
342 @Override
343 public void shutdown() {
344 this.isShutDown = true;
345 synchronized (this) {
346 try {
347 if (uniquePoolEntry != null) {
348 uniquePoolEntry.shutdown();
349 }
350 } catch (final IOException iox) {
351
352 log.debug("Problem while shutting down manager.", iox);
353 } finally {
354 uniquePoolEntry = null;
355 managedConn = null;
356 }
357 }
358 }
359
360 protected void revokeConnection() {
361 final ConnAdapter conn = managedConn;
362 if (conn == null) {
363 return;
364 }
365 conn.detach();
366
367 synchronized (this) {
368 try {
369 uniquePoolEntry.shutdown();
370 } catch (final IOException iox) {
371
372 log.debug("Problem while shutting down connection.", iox);
373 }
374 }
375 }
376
377
378
379
380 protected class PoolEntry extends AbstractPoolEntry {
381
382
383
384
385
386 protected PoolEntry() {
387 super(SingleClientConnManager.this.connOperator, null);
388 }
389
390
391
392
393 protected void close() throws IOException {
394 shutdownEntry();
395 if (connection.isOpen()) {
396 connection.close();
397 }
398 }
399
400
401
402
403 protected void shutdown() throws IOException {
404 shutdownEntry();
405 if (connection.isOpen()) {
406 connection.shutdown();
407 }
408 }
409
410 }
411
412
413
414
415 protected class ConnAdapter extends AbstractPooledConnAdapter {
416
417
418
419
420
421
422
423 protected ConnAdapter(final PoolEntry entry, final HttpRoute route) {
424 super(SingleClientConnManager.this, entry);
425 markReusable();
426 entry.route = route;
427 }
428
429 }
430
431 }