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.hc.client5.testing.async;
29
30 import java.io.IOException;
31 import java.nio.ByteBuffer;
32 import java.util.List;
33 import java.util.concurrent.atomic.AtomicReference;
34
35 import org.apache.hc.core5.concurrent.FutureCallback;
36 import org.apache.hc.core5.http.ContentType;
37 import org.apache.hc.core5.http.EntityDetails;
38 import org.apache.hc.core5.http.Header;
39 import org.apache.hc.core5.http.HttpException;
40 import org.apache.hc.core5.http.HttpRequest;
41 import org.apache.hc.core5.http.HttpStatus;
42 import org.apache.hc.core5.http.MethodNotSupportedException;
43 import org.apache.hc.core5.http.message.BasicHttpResponse;
44 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
45 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
46 import org.apache.hc.core5.http.nio.CapacityChannel;
47 import org.apache.hc.core5.http.nio.DataStreamChannel;
48 import org.apache.hc.core5.http.nio.ResponseChannel;
49 import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityConsumer;
50 import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
51 import org.apache.hc.core5.http.protocol.HttpContext;
52 import org.apache.hc.core5.util.Asserts;
53
54
55
56
57 public class AsyncEchoHandler implements AsyncServerExchangeHandler {
58
59 private final BasicAsyncEntityConsumer entityConsumer;
60 private final AtomicReference<AsyncEntityProducer> entityProducerRef;
61
62 public AsyncEchoHandler() {
63 this.entityConsumer = new BasicAsyncEntityConsumer();
64 this.entityProducerRef = new AtomicReference<>();
65 }
66
67 @Override
68 public void releaseResources() {
69 entityConsumer.releaseResources();
70 final AsyncEntityProducer producer = entityProducerRef.getAndSet(null);
71 if (producer != null) {
72 producer.releaseResources();
73 }
74 }
75
76 @Override
77 public void handleRequest(
78 final HttpRequest request,
79 final EntityDetails entityDetails,
80 final ResponseChannel responseChannel,
81 final HttpContext context) throws HttpException, IOException {
82 final String method = request.getMethod();
83 if (!"GET".equalsIgnoreCase(method) &&
84 !"HEAD".equalsIgnoreCase(method) &&
85 !"POST".equalsIgnoreCase(method) &&
86 !"PUT".equalsIgnoreCase(method)) {
87 throw new MethodNotSupportedException(method + " not supported by " + getClass().getName());
88 }
89 if (entityDetails != null) {
90
91 final ContentType contentType = ContentType.parseLenient(entityDetails.getContentType());
92 entityConsumer.streamStart(entityDetails, new FutureCallback<byte[]>() {
93
94 @Override
95 public void completed(final byte[] content) {
96 final BasicAsyncEntityProducer entityProducer = new BasicAsyncEntityProducer(content, contentType);
97 entityProducerRef.set(entityProducer);
98 try {
99 responseChannel.sendResponse(new BasicHttpResponse(HttpStatus.SC_OK), entityProducer, context);
100 } catch (final IOException | HttpException ex) {
101 failed(ex);
102 }
103 }
104
105 @Override
106 public void failed(final Exception ex) {
107 releaseResources();
108 }
109
110 @Override
111 public void cancelled() {
112 releaseResources();
113 }
114
115 });
116 } else {
117 responseChannel.sendResponse(new BasicHttpResponse(HttpStatus.SC_OK), null, context);
118 entityConsumer.releaseResources();
119 }
120 }
121
122 @Override
123 public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
124 entityConsumer.updateCapacity(capacityChannel);
125 }
126
127 @Override
128 public void consume(final ByteBuffer src) throws IOException {
129 entityConsumer.consume(src);
130 }
131
132 @Override
133 public void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
134 entityConsumer.streamEnd(trailers);
135 }
136
137 @Override
138 public int available() {
139 final AsyncEntityProducer producer = entityProducerRef.get();
140 Asserts.notNull(producer, "Entity producer");
141 return producer.available();
142 }
143
144 @Override
145 public void produce(final DataStreamChannel channel) throws IOException {
146 final AsyncEntityProducer producer = entityProducerRef.get();
147 Asserts.notNull(producer, "Entity producer");
148 producer.produce(channel);
149 }
150
151 @Override
152 public void failed(final Exception cause) {
153 releaseResources();
154 }
155
156 }