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.hc.client5.testing.sync;
28
29 import java.io.IOException;
30
31 import org.apache.hc.client5.http.HttpRoute;
32 import org.apache.hc.client5.http.UserTokenHandler;
33 import org.apache.hc.client5.http.classic.methods.HttpGet;
34 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
35 import org.apache.hc.client5.http.protocol.HttpClientContext;
36 import org.apache.hc.core5.http.ClassicHttpRequest;
37 import org.apache.hc.core5.http.ClassicHttpResponse;
38 import org.apache.hc.core5.http.EndpointDetails;
39 import org.apache.hc.core5.http.HttpException;
40 import org.apache.hc.core5.http.HttpHost;
41 import org.apache.hc.core5.http.HttpStatus;
42 import org.apache.hc.core5.http.io.HttpRequestHandler;
43 import org.apache.hc.core5.http.io.entity.EntityUtils;
44 import org.apache.hc.core5.http.io.entity.StringEntity;
45 import org.apache.hc.core5.http.protocol.BasicHttpContext;
46 import org.apache.hc.core5.http.protocol.HttpContext;
47 import org.junit.Assert;
48 import org.junit.Test;
49
50
51
52
53 public class TestStatefulConnManagement extends LocalServerTestBase {
54
55 private static class SimpleService implements HttpRequestHandler {
56
57 public SimpleService() {
58 super();
59 }
60
61 @Override
62 public void handle(
63 final ClassicHttpRequest request,
64 final ClassicHttpResponse response,
65 final HttpContext context) throws HttpException, IOException {
66 response.setCode(HttpStatus.SC_OK);
67 final StringEntity entity = new StringEntity("Whatever");
68 response.setEntity(entity);
69 }
70 }
71
72 @Test
73 public void testStatefulConnections() throws Exception {
74
75 final int workerCount = 5;
76 final int requestCount = 5;
77
78 this.server.registerHandler("*", new SimpleService());
79
80 this.connManager.setMaxTotal(workerCount);
81 this.connManager.setDefaultMaxPerRoute(workerCount);
82
83 final UserTokenHandler userTokenHandler = new UserTokenHandler() {
84
85 @Override
86 public Object getUserToken(final HttpRoute route, final HttpContext context) {
87 final String id = (String) context.getAttribute("user");
88 return id;
89 }
90
91 };
92 this.clientBuilder.setUserTokenHandler(userTokenHandler);
93
94 final HttpHost target = start();
95
96 final HttpClientContext[] contexts = new HttpClientContext[workerCount];
97 final HttpWorker[] workers = new HttpWorker[workerCount];
98 for (int i = 0; i < contexts.length; i++) {
99 final HttpClientContext context = HttpClientContext.create();
100 contexts[i] = context;
101 workers[i] = new HttpWorker(
102 "user" + i,
103 context, requestCount, target, this.httpclient);
104 }
105
106 for (final HttpWorker worker : workers) {
107 worker.start();
108 }
109 for (final HttpWorker worker : workers) {
110 worker.join(LONG_TIMEOUT.toMilliseconds());
111 }
112 for (final HttpWorker worker : workers) {
113 final Exception ex = worker.getException();
114 if (ex != null) {
115 throw ex;
116 }
117 Assert.assertEquals(requestCount, worker.getCount());
118 }
119
120 for (final HttpContext context : contexts) {
121 final String state0 = (String) context.getAttribute("r0");
122 Assert.assertNotNull(state0);
123 for (int r = 1; r < requestCount; r++) {
124 Assert.assertEquals(state0, context.getAttribute("r" + r));
125 }
126 }
127
128 }
129
130 static class HttpWorker extends Thread {
131
132 private final String uid;
133 private final HttpClientContext context;
134 private final int requestCount;
135 private final HttpHost target;
136 private final CloseableHttpClient httpclient;
137
138 private volatile Exception exception;
139 private volatile int count;
140
141 public HttpWorker(
142 final String uid,
143 final HttpClientContext context,
144 final int requestCount,
145 final HttpHost target,
146 final CloseableHttpClient httpclient) {
147 super();
148 this.uid = uid;
149 this.context = context;
150 this.requestCount = requestCount;
151 this.target = target;
152 this.httpclient = httpclient;
153 this.count = 0;
154 }
155
156 public int getCount() {
157 return this.count;
158 }
159
160 public Exception getException() {
161 return this.exception;
162 }
163
164 @Override
165 public void run() {
166 try {
167 this.context.setAttribute("user", this.uid);
168 for (int r = 0; r < this.requestCount; r++) {
169 final HttpGet httpget = new HttpGet("/");
170 final ClassicHttpResponse response = this.httpclient.execute(
171 this.target,
172 httpget,
173 this.context);
174 this.count++;
175
176 final EndpointDetails endpointDetails = this.context.getEndpointDetails();
177 final String connuid = Integer.toHexString(System.identityHashCode(endpointDetails));
178 this.context.setAttribute("r" + r, connuid);
179 EntityUtils.consume(response.getEntity());
180 }
181
182 } catch (final Exception ex) {
183 this.exception = ex;
184 }
185 }
186
187 }
188
189 @Test
190 public void testRouteSpecificPoolRecylcing() throws Exception {
191
192
193
194
195 final int maxConn = 2;
196
197 this.server.registerHandler("*", new SimpleService());
198
199 this.connManager.setMaxTotal(maxConn);
200 this.connManager.setDefaultMaxPerRoute(maxConn);
201
202 final UserTokenHandler userTokenHandler = new UserTokenHandler() {
203
204 @Override
205 public Object getUserToken(final HttpRoute route, final HttpContext context) {
206 return context.getAttribute("user");
207 }
208
209 };
210
211 this.clientBuilder.setUserTokenHandler(userTokenHandler);
212
213 final HttpHost target = start();
214
215
216 final HttpContext context1 = new BasicHttpContext();
217 context1.setAttribute("user", "stuff");
218 final ClassicHttpResponse response1 = this.httpclient.execute(
219 target, new HttpGet("/"), context1);
220 EntityUtils.consume(response1.getEntity());
221
222
223
224
225
226 Thread.sleep(100);
227
228
229
230 final HttpContext context2 = new BasicHttpContext();
231 final ClassicHttpResponse response2 = this.httpclient.execute(
232 new HttpHost("127.0.0.1", this.server.getPort()), new HttpGet("/"), context2);
233 EntityUtils.consume(response2.getEntity());
234
235
236
237
238 Thread.sleep(100);
239
240
241
242
243
244
245 final HttpContext context3 = new BasicHttpContext();
246 final ClassicHttpResponse response3 = this.httpclient.execute(
247 target, new HttpGet("/"), context3);
248
249
250
251
252 EntityUtils.consume(response3.getEntity());
253
254 }
255
256 }