1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.search.api.transport;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.net.URI;
24 import java.net.http.HttpClient;
25 import java.net.http.HttpRequest;
26 import java.net.http.HttpResponse;
27 import java.time.Duration;
28 import java.util.AbstractMap;
29 import java.util.Map;
30 import java.util.stream.Collectors;
31
32 import static java.util.Objects.requireNonNull;
33
34
35
36
37 public class Java11HttpClientTransport implements Transport {
38 protected static class ResponseImpl implements Response {
39
40 protected final HttpResponse<?> response;
41
42 protected final InputStream inputStream;
43
44 protected ResponseImpl(HttpResponse<?> response, InputStream inputStream) {
45 this.response = requireNonNull(response);
46 this.inputStream = inputStream;
47 }
48
49 @Override
50 public int getCode() {
51 return response.statusCode();
52 }
53
54 @Override
55 public Map<String, String> getHeaders() {
56 return response.headers().map().entrySet().stream()
57 .map(e -> new AbstractMap.SimpleEntry<>(
58 e.getKey(), e.getValue().get(0)))
59 .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
60 }
61
62 @Override
63 public InputStream getBody() {
64 return inputStream;
65 }
66
67 @Override
68 public void close() throws IOException {
69 if (inputStream != null) {
70 inputStream.close();
71 }
72 }
73
74 @Override
75 public String toString() {
76 return response.uri() + " -> " + response.version() + " " + response.statusCode();
77 }
78 }
79
80 protected final Duration timeout;
81
82 protected final HttpClient client;
83
84 public Java11HttpClientTransport() {
85 this(Duration.ofSeconds(10L));
86 }
87
88 public Java11HttpClientTransport(Duration timeout) {
89 this(
90 timeout,
91 HttpClient.newBuilder()
92 .connectTimeout(timeout)
93 .followRedirects(HttpClient.Redirect.NEVER)
94 .build());
95 }
96
97 public Java11HttpClientTransport(Duration timeout, HttpClient client) {
98 this.timeout = requireNonNull(timeout);
99 this.client = requireNonNull(client);
100 }
101
102 @Override
103 public Response get(String serviceUri, Map<String, String> headers) throws IOException {
104 HttpRequest.Builder builder = HttpRequest.newBuilder()
105 .timeout(timeout)
106 .uri(URI.create(serviceUri))
107 .GET();
108 for (Map.Entry<String, String> header : headers.entrySet()) {
109 builder.header(header.getKey(), header.getValue());
110 }
111 HttpRequest request = builder.build();
112 try {
113 HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
114 return new ResponseImpl(response, response.body());
115 } catch (InterruptedException e) {
116 Thread.currentThread().interrupt();
117 throw new IOException(e);
118 }
119 }
120
121 @Override
122 public Response head(String serviceUri, Map<String, String> headers) throws IOException {
123 HttpRequest.Builder builder = HttpRequest.newBuilder()
124 .timeout(timeout)
125 .uri(URI.create(serviceUri))
126 .method("HEAD", HttpRequest.BodyPublishers.noBody());
127 for (Map.Entry<String, String> header : headers.entrySet()) {
128 builder.header(header.getKey(), header.getValue());
129 }
130 HttpRequest request = builder.build();
131 try {
132 HttpResponse<Void> response = client.send(request, HttpResponse.BodyHandlers.discarding());
133 return new ResponseImpl(response, null);
134 } catch (InterruptedException e) {
135 Thread.currentThread().interrupt();
136 throw new IOException(e);
137 }
138 }
139 }