68 |
68 |
69 /** |
69 /** |
70 * Exercise 1. |
70 * Exercise 1. |
71 * |
71 * |
72 * Retrieve the response status code from a request to the given |
72 * Retrieve the response status code from a request to the given |
73 * URI. The returned response code will be a int. |
73 * URI. Return the response code, which is an integer. |
74 * |
74 * |
75 * Hint: use the discard BodyHandler since the response body is not |
75 * Hint: use the {@link BodyHandler#discard(Object)BodyHandler} since |
76 * interesting. |
76 * the response body is not interesting. |
77 * |
77 * |
78 * Hint: static imports reduce boilerplate when using BodyHandlers |
78 * Hint: static imports reduce boilerplate when using BodyHandlers |
79 * and BodyProcessors, e.g. import static |
79 * and BodyProcessors, e.g. import static |
80 * jdk.incubator.http.HttpResponse.BodyHandler.discard |
80 * jdk.incubator.http.HttpResponse.BodyHandler.discard |
81 */ |
81 */ |
88 |
88 |
89 return response.statusCode(); |
89 return response.statusCode(); |
90 } |
90 } |
91 |
91 |
92 /** |
92 /** |
93 * Exercise 1. |
93 * Exercise 2. |
94 * |
94 * |
95 * Retrieve the response body from a given URI. Return the response |
95 * Retrieve the response body from a given URI. Return the response |
96 * body as a String. |
96 * body as a String. |
97 * |
97 * |
98 * Hint: use the asString BodyHandler to convert the HTTP response |
98 * Hint: use the {@link BodyHandler#asString()} BodyHandler to convert |
99 * body to a String. |
99 * the HTTP response body to a String. |
100 * |
100 * |
101 * Hint: static imports reduce boilerplate when using BodyHandlers |
101 * Hint: static imports reduce boilerplate when using BodyHandlers |
102 * and BodyProcessors, e.g. import static |
102 * and BodyProcessors, e.g. import static |
103 * jdk.incubator.http.HttpResponse.BodyHandler.asString |
103 * jdk.incubator.http.HttpResponse.BodyHandler.asString |
104 */ |
104 */ |
111 |
111 |
112 return response.body(); |
112 return response.body(); |
113 } |
113 } |
114 |
114 |
115 /** |
115 /** |
116 * Exercise 2. |
116 * Exercise 3. |
117 * |
117 * |
118 * Retrieve the response body from a given URI, streaming teh body |
118 * Retrieve the response body from a given URI, streaming the body |
119 * out to a file. Return the file's Path. |
119 * out to a file. Return the file's Path. |
120 * |
120 * |
121 * Hint: use {@linkplain BodyHandler#asFile} to stream the HTTP |
121 * Hint: use {@linkplain BodyHandler#asFile} to stream the HTTP |
122 * response body to a file. |
122 * response body to a file. |
|
123 * |
|
124 * Hint: if a file already exists from a previous test run, either |
|
125 * remove it or use the {@link java.nio.file.StandardOpenOption#CREATE} |
|
126 * along with the {@link java.nio.file.StandardOpenOption#TRUNCATE_EXISTING} |
|
127 * to create or truncate as needed. |
123 */ |
128 */ |
124 public static Path retrieveResourceAsFile(URI uri) |
129 public static Path retrieveResourceAsFile(URI uri) |
125 throws IOException, InterruptedException |
130 throws IOException, InterruptedException |
126 { |
131 { |
127 HttpClient client = HttpClient.newBuilder().build(); |
132 HttpClient client = HttpClient.newBuilder().build(); |
129 .uri(uri) |
134 .uri(uri) |
130 .version(HTTP_1_1) |
135 .version(HTTP_1_1) |
131 .GET() |
136 .GET() |
132 .build(); |
137 .build(); |
133 HttpResponse<Path> response = client.send(request, |
138 HttpResponse<Path> response = client.send(request, |
134 asFile(Paths.get("retrieveResourceAsFile.txt"), StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)); |
139 asFile(Paths.get("retrieveResourceAsFile.txt"), |
135 |
140 StandardOpenOption.CREATE, |
136 System.out.println("CHEGAR: sc=" + response.statusCode()); |
141 StandardOpenOption.TRUNCATE_EXISTING, |
137 System.out.println("CHEGAR: by=" + Files.readAllLines(response.body()).stream().collect(joining())); |
142 StandardOpenOption.WRITE)); |
138 |
|
139 return response.body(); |
143 return response.body(); |
140 } |
144 } |
141 |
145 |
142 |
146 |
143 /** |
147 /** |
144 * Asserts that the response code is 200 ( OK ). |
148 * A helper method, NOT an exercise. |
|
149 * |
|
150 * Asserts that the response code is 200 ( OK ). Throws IOException if |
|
151 * the response code is not 200. |
145 * |
152 * |
146 * Can be used in CompletableFuture pipelines when checking the |
153 * Can be used in CompletableFuture pipelines when checking the |
147 * response of an {@linkplain HttpClient#sendAsync} call. For |
154 * response of an {@linkplain HttpClient#sendAsync} call. For |
148 * example: |
155 * example: |
149 * client.sendAsync(request, bodyHandler) |
156 * client.sendAsync(request, bodyHandler) |
159 } |
166 } |
160 return response; |
167 return response; |
161 } |
168 } |
162 |
169 |
163 /** |
170 /** |
164 * Exercise 3. |
171 * Exercise 4. |
165 * |
172 * |
166 * Retrieve the response body from a given URI, using the |
173 * Retrieve the response body from a given URI, using thea synchronous |
167 * asynchronous send API, sendAsync. Return a CompletableFuture that |
174 * send API, {@link HttpClient#sendAsync(HttpRequest, BodyHandler)}. |
168 * completes with the response body as a String. |
175 * Return a CompletableFuture that completes with the response body |
|
176 * as a String. |
169 * |
177 * |
170 * Hint: The {@linkplain CompletableFuture#thenApply(Function)} |
178 * Hint: The {@linkplain CompletableFuture#thenApply(Function)} |
171 * method can be used to map the HttpResponse to a String. |
179 * method can be used to map the HttpResponse to a String. |
172 */ |
180 */ |
173 public static CompletableFuture<String> retrieveResourceAsStringUsingAsyncAPI(URI uri) { |
181 public static CompletableFuture<String> retrieveResourceAsStringUsingAsyncAPI(URI uri) { |
|
182 // TODO: why version needed? |
|
183 |
174 return HttpClient.newHttpClient() |
184 return HttpClient.newHttpClient() |
175 .sendAsync(HttpRequest.newBuilder(uri).version(HTTP_1_1).build(), asString()) // TODO: why version needed? |
185 .sendAsync(HttpRequest.newBuilder(uri).version(HTTP_1_1).build(), asString()) |
176 .thenApply(Retrievals::require200StatusCode) |
186 .thenApply(Retrievals::require200StatusCode) |
177 .thenApply(HttpResponse::body); |
187 .thenApply(HttpResponse::body); |
178 } |
188 } |
179 |
189 |
180 |
190 |
181 /** |
191 /** |
|
192 * A helper method, NOT an exercise. |
|
193 * |
182 * Wrapper around Jackson's ObjectMapper that provides an unchecked |
194 * Wrapper around Jackson's ObjectMapper that provides an unchecked |
183 * {@code readValue}, what can be used to help solve the next |
195 * {@code readValue}, what can be used to help solve the next |
184 * exercise, 4. |
196 * exercise, 5. |
185 */ |
197 */ |
186 public static class UncheckedObjectMapper extends ObjectMapper { |
198 public static class UncheckedObjectMapper extends ObjectMapper { |
187 |
199 |
188 /** Parses the given JSON string into a Map. */ |
200 /** Parses the given JSON string into a Map. */ |
189 Map<String,String> readValue(String content) { |
201 Map<String,String> readValue(String content) { |
194 } |
206 } |
195 } |
207 } |
196 } |
208 } |
197 |
209 |
198 /** |
210 /** |
199 * Exercise 4. |
211 * Exercise 5. |
200 * |
212 * |
201 * Retrieve the response body from a given URI. The response body |
213 * Retrieve the response body from a given URI. The response body |
202 * will be in the JSON format. The Jackson based UncheckedObjectMapper |
214 * will be in the JSON format. The Jackson based UncheckedObjectMapper |
203 * ( above ) can be used to parse the String response body into a |
215 * ( above ) can be used to parse the String response body into a |
204 * Map. |
216 * Map. Return the response body as a Map. |
205 * |
217 * |
206 * Hint: The asynchronous send API will allow construction of a |
218 * Hint: The asynchronous send API will allow construction of a |
207 * pipeline of CompletableFutures. |
219 * pipeline of CompletableFutures. |
208 * |
220 * |
209 * Hint: The {@linkplain CompletableFuture#thenApply(Function)} |
221 * Hint: The {@linkplain CompletableFuture#thenApply(Function)} |
210 * method can be used to map the HttpResponse to a String, and then |
222 * method can be used to map the HttpResponse to a String, and then |
211 * again from a Sting to a Map ( via the object mapper ). |
223 * again from a String ( of JSON ) to a Map ( via the object mapper ). |
212 */ |
224 */ |
213 public CompletableFuture<Map<String,String>> JSONBodyAsMap(URI uri) { |
225 public CompletableFuture<Map<String,String>> JSONBodyAsMap(URI uri) { |
214 UncheckedObjectMapper objectMapper = new UncheckedObjectMapper(); |
226 UncheckedObjectMapper objectMapper = new UncheckedObjectMapper(); |
215 return HttpClient.newHttpClient() |
227 return HttpClient.newHttpClient() |
216 .sendAsync(HttpRequest.newBuilder(uri).version(HTTP_1_1).build(), asString()) |
228 .sendAsync(HttpRequest.newBuilder(uri).version(HTTP_1_1).build(), asString()) |
219 } |
231 } |
220 |
232 |
221 |
233 |
222 |
234 |
223 /** |
235 /** |
|
236 * Exercise 6. |
|
237 * |
224 * Post the given {@code data}, and receive the same data in |
238 * Post the given {@code data}, and receive the same data in |
225 * response. Return the response body data as a String. |
239 * response. Return the response body data as a String. |
226 */ |
240 */ |
227 public static String postData(URI uri, String data) |
241 public static String postData(URI uri, String data) |
228 throws IOException, InterruptedException |
242 throws IOException, InterruptedException |