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.execchain;
29
30 import java.io.Closeable;
31 import java.io.IOException;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.atomic.AtomicBoolean;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.http.HttpClientConnection;
37 import org.apache.http.annotation.Contract;
38 import org.apache.http.annotation.ThreadingBehavior;
39 import org.apache.http.concurrent.Cancellable;
40 import org.apache.http.conn.ConnectionReleaseTrigger;
41 import org.apache.http.conn.HttpClientConnectionManager;
42
43
44
45
46
47
48 @Contract(threading = ThreadingBehavior.SAFE)
49 class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeable {
50
51 private final Log log;
52
53 private final HttpClientConnectionManager manager;
54 private final HttpClientConnection managedConn;
55 private final AtomicBoolean released;
56 private volatile boolean reusable;
57 private volatile Object state;
58 private volatile long validDuration;
59 private volatile TimeUnit timeUnit;
60
61 public ConnectionHolder(
62 final Log log,
63 final HttpClientConnectionManager manager,
64 final HttpClientConnection managedConn) {
65 super();
66 this.log = log;
67 this.manager = manager;
68 this.managedConn = managedConn;
69 this.released = new AtomicBoolean(false);
70 }
71
72 public boolean isReusable() {
73 return this.reusable;
74 }
75
76 public void markReusable() {
77 this.reusable = true;
78 }
79
80 public void markNonReusable() {
81 this.reusable = false;
82 }
83
84 public void setState(final Object state) {
85 this.state = state;
86 }
87
88 public void setValidFor(final long duration, final TimeUnit timeUnit) {
89 synchronized (this.managedConn) {
90 this.validDuration = duration;
91 this.timeUnit = timeUnit;
92 }
93 }
94
95 private void releaseConnection(final boolean reusable) {
96 if (this.released.compareAndSet(false, true)) {
97 synchronized (this.managedConn) {
98 if (reusable) {
99 this.manager.releaseConnection(this.managedConn,
100 this.state, this.validDuration, this.timeUnit);
101 } else {
102 try {
103 this.managedConn.close();
104 log.debug("Connection discarded");
105 } catch (final IOException ex) {
106 if (this.log.isDebugEnabled()) {
107 this.log.debug(ex.getMessage(), ex);
108 }
109 } finally {
110 this.manager.releaseConnection(
111 this.managedConn, null, 0, TimeUnit.MILLISECONDS);
112 }
113 }
114 }
115 }
116 }
117
118 @Override
119 public void releaseConnection() {
120 releaseConnection(this.reusable);
121 }
122
123 @Override
124 public void abortConnection() {
125 if (this.released.compareAndSet(false, true)) {
126 synchronized (this.managedConn) {
127 try {
128 this.managedConn.shutdown();
129 log.debug("Connection discarded");
130 } catch (final IOException ex) {
131 if (this.log.isDebugEnabled()) {
132 this.log.debug(ex.getMessage(), ex);
133 }
134 } finally {
135 this.manager.releaseConnection(
136 this.managedConn, null, 0, TimeUnit.MILLISECONDS);
137 }
138 }
139 }
140 }
141
142 @Override
143 public boolean cancel() {
144 final boolean alreadyReleased = this.released.get();
145 log.debug("Cancelling request execution");
146 abortConnection();
147 return !alreadyReleased;
148 }
149
150 public boolean isReleased() {
151 return this.released.get();
152 }
153
154 @Override
155 public void close() throws IOException {
156 releaseConnection(false);
157 }
158
159 }