001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest.client2; 014 015import static org.apache.juneau.internal.StringUtils.*; 016import static org.apache.juneau.AddFlag.*; 017import static org.apache.juneau.httppart.HttpPartType.*; 018import static org.apache.juneau.http.HttpMethod.*; 019import static java.util.logging.Level.*; 020import static org.apache.juneau.internal.StateMachineState.*; 021import static java.lang.Character.*; 022 023import java.io.*; 024import java.lang.reflect.*; 025import java.lang.reflect.Proxy; 026import java.net.*; 027import java.net.URI; 028import java.nio.charset.*; 029import java.text.*; 030import java.util.*; 031import java.util.concurrent.*; 032import java.util.function.*; 033import java.util.logging.*; 034import java.util.regex.*; 035 036import org.apache.http.*; 037import org.apache.http.client.*; 038import org.apache.http.client.config.*; 039import org.apache.http.client.entity.*; 040import org.apache.http.client.methods.*; 041import org.apache.http.client.utils.*; 042import org.apache.http.conn.*; 043import org.apache.http.entity.*; 044import org.apache.http.entity.BasicHttpEntity; 045import org.apache.http.impl.client.*; 046import org.apache.http.params.*; 047import org.apache.http.protocol.*; 048import org.apache.juneau.*; 049import org.apache.juneau.annotation.*; 050import org.apache.juneau.assertions.*; 051import org.apache.juneau.collections.*; 052import org.apache.juneau.http.remote.RemoteReturn; 053import org.apache.juneau.http.*; 054import org.apache.juneau.http.header.*; 055import org.apache.juneau.http.remote.*; 056import org.apache.juneau.httppart.*; 057import org.apache.juneau.httppart.bean.*; 058import org.apache.juneau.internal.*; 059import org.apache.juneau.marshall.*; 060import org.apache.juneau.oapi.*; 061import org.apache.juneau.parser.*; 062import org.apache.juneau.parser.ParseException; 063import org.apache.juneau.reflect.*; 064import org.apache.juneau.rest.client.remote.*; 065import org.apache.juneau.serializer.*; 066import org.apache.juneau.urlencoding.*; 067import org.apache.juneau.utils.*; 068 069/** 070 * Utility class for interfacing with remote REST interfaces. 071 * 072 * <p class='w900'> 073 * Built upon the feature-rich Apache HttpClient library, the Juneau RestClient API adds support for fluent-style 074 * REST calls and the ability to perform marshalling of POJOs to and from HTTP parts. 075 * 076 * <h5 class='figure'>Example:</h5> 077 * <p class='bcode w800'> 078 * <jc>// Create a basic REST client with JSON support and download a bean.</jc> 079 * MyBean <jv>bean</jv> = RestClient.<jsm>create</jsm>() 080 * .simpleJson() 081 * .build() 082 * .get(<jsf>URI</jsf>) 083 * .run() 084 * .assertStatus().code().is(200) 085 * .assertHeader(<js>"Content-Type"</js>).matchesSimple(<js>"application/json*"</js>) 086 * .getBody().as(MyBean.<jk>class</jk>); 087 * </p> 088 * 089 * <p class='w900'> 090 * Breaking apart the fluent call, we can see the classes being used: 091 * <p class='bcode w800'> 092 * RestClientBuilder <jv>builder</jv> = RestClient.<jsm>create</jsm>().simpleJson(); 093 * RestClient <jv>client</jv> = <jv>builder</jv>.build(); 094 * RestRequest <jv>req</jv> = <jv>client</jv>.get(<jsf>URI</jsf>); 095 * RestResponse <jv>res</jv> = <jv>req</jv>.run(); 096 * RestResponseStatusLineAssertion <jv>statusLineAssertion</jv> = <jv>res</jv>.assertStatus(); 097 * FluentIntegerAssertion<RestResponse> <jv>codeAssertion</jv> = <jv>statusLineAssertion</jv>.code(); 098 * <jv>res</jv> = <jv>codeAssertion</jv>.is(200); 099 * FluentStringAssertion<RestResponse> <jv>headerAssertion</jv> = <jv>res</jv>.assertHeader(<js>"Content-Type"</js>); 100 * <jv>res</jv> = <jv>headerAssertion</jv>.matchesSimple(<js>"application/json*"</js>); 101 * RestResponseBody <jv>body</jv> = <jv>res</jv>.getBody(); 102 * MyBean <jv>bean</jv> = <jv>body</jv>.as(MyBean.<jk>class</jk>); 103 * </p> 104 * 105 * <p class='w900'> 106 * It additionally provides support for creating remote proxy interfaces using REST as the transport medium. 107 * 108 * <h5 class='figure'>Example:</h5> 109 * <p class='bcode w800'> 110 * <jc>// Define a Remote proxy for interacting with a REST interface.</jc> 111 * <ja>@Remote</ja>(path=<js>"/petstore"</js>) 112 * <jk>public interface</jk> PetStore { 113 * 114 * <ja>@RemoteMethod</ja>(httpMethod=<jsf>POST</jsf>, path=<js>"/pets"</js>) 115 * Pet addPet( 116 * <ja>@Body</ja> CreatePet <jv>pet</jv>, 117 * <ja>@Header</ja>(<js>"E-Tag"</js>) UUID <jv>etag</jv>, 118 * <ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> <jv>debug</jv> 119 * ); 120 * } 121 * 122 * <jc>// Use a RestClient with default Simple JSON support.</jc> 123 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build(); 124 * 125 * PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>); 126 * CreatePet <jv>createPet</jv> = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99); 127 * Pet <jv>pet</jv> = <jv>store</jv>.addPet(<jv>createPet</jv>, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>); 128 * </p> 129 * 130 * <p class='w900'> 131 * The classes are closely tied to Apache HttpClient, yet provide lots of additional functionality: 132 * <ul class='javatree'> 133 * <li class='jc'>{@link RestClient} <jk>extends</jk> {@link HttpClient}, creates {@link RestRequest} objects. 134 * <li class='jc'>{@link RestRequest} <jk>extends</jk> {@link HttpUriRequest}, creates {@link RestResponse} objects. 135 * <li class='jc'>{@link RestResponse} <jk>extends</jk> {@link HttpResponse}, creates {@link RestResponseBody} and {@link RestResponseHeader} objects. 136 * <li class='jc'>{@link RestResponseBody} <jk>extends</jk> {@link HttpEntity} 137 * <li class='jc'>{@link RestResponseHeader} <jk>extends</jk> {@link Header} 138 * </ul> 139 * 140 * 141 * <p class='w900'> 142 * Instances of this class are built using the {@link RestClientBuilder} class which can be constructed using 143 * the {@link #create() RestClient.create()} method as shown above. 144 * 145 * <p class='w900'> 146 * Clients are typically created with a root URI so that relative URIs can be used when making requests. 147 * This is done using the {@link RestClientBuilder#rootUri(Object)} method. 148 * 149 * <h5 class='figure'>Example:</h5> 150 * <p class='bcode w800'> 151 * <jc>// Create a client where all URIs are relative to localhost.</jc> 152 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().rootUri(<js>"http://localhost:5000"</js>).build(); 153 * 154 * <jc>// Use relative paths.</jc> 155 * String <jv>body</jv> = <jv>client</jv>.get(<js>"/subpath"</js>).run().getBody().asString(); 156 * </p> 157 * 158 * <p class='w900'> 159 * The {@link RestClient} class creates {@link RestRequest} objects using the following methods: 160 * 161 * <ul class='javatree'> 162 * <li class='jc'>{@link RestClient} 163 * <ul> 164 * <li class='jm'>{@link RestClient#get(Object) get(uri)} / {@link RestClient#get() get()} 165 * <li class='jm'>{@link RestClient#put(Object,Object) put(uri,body)} / {@link RestClient#put(Object) put(uri)} 166 * <li class='jm'>{@link RestClient#post(Object) post(uri,body)} / {@link RestClient#post(Object) post(uri)} 167 * <li class='jm'>{@link RestClient#patch(Object,Object) patch(uri,body)} / {@link RestClient#patch(Object) patch(uri)} 168 * <li class='jm'>{@link RestClient#delete(Object) delete(uri)} 169 * <li class='jm'>{@link RestClient#head(Object) head(uri)} 170 * <li class='jm'>{@link RestClient#options(Object) options(uri)} 171 * <li class='jm'>{@link RestClient#formPost(Object,Object) formPost(uri,body)} / {@link RestClient#formPost(Object) formPost(uri)} 172 * <li class='jm'>{@link RestClient#formPostPairs(Object,Object...) formPostPairs(uri,parameters...)} 173 * <li class='jm'>{@link RestClient#request(String,Object,Object) request(method,uri,body)} 174 * </ul> 175 * </ul> 176 * 177 * <p class='w900'> 178 * The {@link RestRequest} class creates {@link RestResponse} objects using the following methods: 179 * 180 * <ul class='javatree'> 181 * <li class='jc'>{@link RestRequest} 182 * <ul> 183 * <li class='jm'>{@link RestRequest#run() run()} 184 * <li class='jm'>{@link RestRequest#complete() complete()} 185 * </ul> 186 * </ul> 187 * 188 * <p class='w900'> 189 * The distinction between the two methods is that {@link RestRequest#complete() complete()} automatically consumes the response body and 190 * {@link RestRequest#run() run()} does not. Note that you must consume response bodies in order for HTTP connections to be freed up 191 * for reuse! The {@link InputStream InputStreams} returned by the {@link RestResponseBody} object are auto-closing once 192 * they are exhausted, so it is often not necessary to explicitly close them. 193 * 194 * <p class='w900'> 195 * The following examples show the distinction between the two calls: 196 * 197 * <p class='bcode w800'> 198 * <jc>// Consuming the response, so use run().</jc> 199 * String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().asString(); 200 * 201 * <jc>// Only interested in response status code, so use complete().</jc> 202 * <jk>int</jk> <jv>status</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode(); 203 * </p> 204 * 205 * 206 * <h4 class='topic'>POJO Marshalling</h4> 207 * 208 * <p class='w900'> 209 * By default, JSON support is provided for HTTP request and response bodies. 210 * Other languages can be specified using any of the following builder methods: 211 * <ul class='javatree'> 212 * <li class='jc'>{@link RestClientBuilder} 213 * <ul> 214 * <li class='jm'>{@link RestClientBuilder#json() json()} 215 * <li class='jm'>{@link RestClientBuilder#simpleJson() simpleJson()} 216 * <li class='jm'>{@link RestClientBuilder#xml() xml()} 217 * <li class='jm'>{@link RestClientBuilder#html() html()} 218 * <li class='jm'>{@link RestClientBuilder#plainText() plainText()} 219 * <li class='jm'>{@link RestClientBuilder#msgPack() msgPack()} 220 * <li class='jm'>{@link RestClientBuilder#uon() uon()} 221 * <li class='jm'>{@link RestClientBuilder#urlEnc() urlEnc()} 222 * <li class='jm'>{@link RestClientBuilder#openApi() openApi()} 223 * </ul> 224 * </ul> 225 * 226 * <h5 class='figure'>Example:</h5> 227 * <p class='bcode w800'> 228 * <jc>// Create a basic REST client with Simplified-JSON support.</jc> 229 * <jc>// Typically easier to use when performing unit tests.</jc> 230 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build(); 231 * </p> 232 * 233 * <p> 234 * Clients can also support multiple languages: 235 * 236 * <h5 class='figure'>Example:</h5> 237 * <p class='bcode w800'> 238 * <jc>// Create a REST client with support for multiple languages.</jc> 239 * RestClient <jv>client1</jv> = RestClient.<jsm>create</jsm>().json().xml().openApi().build(); 240 * 241 * <jc>// Create a REST client with support for all supported languages.</jc> 242 * RestClient <jv>client2</jv> = RestClient.<jsm>create</jsm>().universal().build(); 243 * </p> 244 * 245 * <p class='w900'> 246 * When using clients with multiple language support, you must specify the <c>Content-Type</c> header on requests 247 * with bodies to specify which serializer should be selected. 248 * 249 * <p class='bcode w800'> 250 * <jc>// Create a REST client with support for multiple languages.</jc> 251 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().universal().build(); 252 * 253 * <jv>client</jv> 254 * .post(<jsf>URI</jsf>, <jv>myBean</jv>) 255 * .contentType(<js>"application/json"</js>) 256 * .complete() 257 * .assertStatus().is(200); 258 * </p> 259 * 260 * <p> 261 * Languages can also be specified per-request. 262 * 263 * <p class='bcode w800'> 264 * <jc>// Create a REST client with no default languages supported.</jc> 265 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().build(); 266 * 267 * <jc>// Use JSON for this request.</jc> 268 * <jv>client</jv> 269 * .post(<jsf>URI</jsf>, <jv>myBean</jv>) 270 * .json() 271 * .complete() 272 * .assertStatus().is(200); 273 * </p> 274 * 275 * 276 * <p class='w900'> 277 * The {@link RestClientBuilder} class provides convenience methods for setting common serializer and parser 278 * settings. 279 * 280 * <h5 class='figure'>Example:</h5> 281 * <p class='bcode w800'> 282 * <jc>// Create a basic REST client with JSON support.</jc> 283 * <jc>// Use single-quotes and whitespace.</jc> 284 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().sq().ws().build(); 285 * 286 * <jc>// Same, but using properties.</jc> 287 * RestClient <jv>client2</jv> = RestClient 288 * .<jsm>create</jsm>() 289 * .json() 290 * .set(<jsf>WSERIALIZER_quoteChar</jsf>, <js>'\''</js>) 291 * .set(<jsf>WSERIALIZER_useWhitespace</jsf>, <jk>true</jk>) 292 * .build(); 293 * </p> 294 * 295 * <p class='w900'> 296 * Other methods are also provided for specifying the serializers and parsers used for lower-level marshalling support: 297 * <ul class='javatree'> 298 * <li class='jc'>{@link RestClientBuilder} 299 * <ul> 300 * <li class='jm'>{@link RestClientBuilder#serializer(Serializer) serializer(Serializer)} 301 * <li class='jm'>{@link RestClientBuilder#parser(Parser) parser(Parser)} 302 * <li class='jm'>{@link RestClientBuilder#marshall(Marshall) marshall(Marshall)} 303 * </ul> 304 * </ul> 305 * 306 * <p class='w900'> 307 * HTTP parts (headers, query parameters, form data...) are serialized and parsed using the {@link HttpPartSerializer} 308 * and {@link HttpPartParser} APIs. By default, clients are configured to use {@link OpenApiSerializer} and 309 * {@link OpenApiParser}. These can be overridden using the following methods: 310 * <ul class='javatree'> 311 * <li class='jc'>{@link RestClientBuilder} 312 * <ul> 313 * <li class='jm'>{@link RestClientBuilder#partSerializer(Class) partSerializer(Class<? extends HttpPartSerializer>)} 314 * <li class='jm'>{@link RestClientBuilder#partParser(Class) partParser(Class<? extends HttpPartParser>)} 315 * </ul> 316 * </ul> 317 * 318 * 319 * <h4 class='topic'>Request Headers</h4> 320 * <p class='w900'> 321 * Per-client or per-request headers can be specified using the following methods: 322 * <ul class='javatree'> 323 * <li class='jc'>{@link RestClientBuilder} 324 * <ul> 325 * <li class='jm'>{@link RestClientBuilder#header(String,Object) header(String,Object)} 326 * <li class='jm'>{@link RestClientBuilder#header(String,Object,HttpPartSchema) header(String,Object,HttpPartSchema)} 327 * <li class='jm'>{@link RestClientBuilder#header(String,Supplier) header(String,Supplier<?>)} 328 * <li class='jm'>{@link RestClientBuilder#header(String,Supplier,HttpPartSchema) header(String,Supplier<?>,HttpPartSchema)} 329 * <li class='jm'>{@link RestClientBuilder#header(Header) header(Header)} 330 * <li class='jm'>{@link RestClientBuilder#headers(Object...) headers(Object...)} 331 * <li class='jm'>{@link RestClientBuilder#headerPairs(Object...) headerPairs(Object...)} 332 * </ul> 333 * <li class='jc'>{@link RestRequest} 334 * <ul> 335 * <li class='jm'>{@link RestRequest#header(String,Object) header(String,Object)} 336 * <li class='jm'>{@link RestRequest#header(String,Object,HttpPartSchema) header(String,Object,HttpPartSchema)} 337 * <li class='jm'>{@link RestRequest#header(AddFlag,String,Object) header(AddFlag,String,Object)} 338 * <li class='jm'>{@link RestRequest#header(AddFlag,String,Object,HttpPartSchema) header(AddFlag,String,Object,HttpPartSchema)} 339 * <li class='jm'>{@link RestRequest#header(Header) header(Header)} 340 * <li class='jm'>{@link RestRequest#headers(Object...) headers(Object...)} 341 * <li class='jm'>{@link RestRequest#headers(AddFlag,Object...) headers(AddFlag;Object...)} 342 * <li class='jm'>{@link RestRequest#headerPairs(Object...) headers(Object...)} 343 * </ul> 344 * </ul> 345 * 346 * <p> 347 * Additionally, methods are provided on the client builder and per request for all standard HTTP headers 348 * such as {@link RestClientBuilder#authorization(Object) authorization(Object)}. 349 * 350 * <h5 class='figure'>Example:</h5> 351 * <p class='bcode w800'> 352 * <jc>// Create a client that adds an Authorization header to every request.</jc> 353 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().authorization(<js>"Foo"</js>).build(); 354 * 355 * <jc>// Or do it per-request.</jc> 356 * String <jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).authorization(<js>"Foo"</js>).run().getBody().asString(); 357 * 358 * <jc>// Or use an HttpHeader.</jc> 359 * <jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).headers(Authorization.<jsm>of</jsm>(<js>"Foo"</js>)).run().getBody().asString(); 360 * </p> 361 * 362 * <p class='w900'> 363 * The supplier methods are particularly useful for header values whose values may change over time (such as <c>Authorization</c> headers 364 * which may need to change every few minutes). 365 * </p> 366 * 367 * <h5 class='figure'>Example:</h5> 368 * <p class='bcode w800'> 369 * <jc>// Create a client that adds a dynamic Authorization header to every request.</jc> 370 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().header(<js>"Authorization"</js>, ()->getMyAuthToken()).build(); 371 * </p> 372 * 373 * <p> 374 * The {@link HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on both requests 375 * and responses. 376 * 377 * <h5 class='figure'>Example:</h5> 378 * <p class='bcode w800'> 379 * <jc>// Create a client that adds a header "Foo: bar|baz" to every request.</jc> 380 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>() 381 * .header(<js>"Foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), <jsf>T_ARRAY_PIPES</jsf>) 382 * .build(); 383 * </p> 384 * 385 * <p> 386 * The methods with {@link AddFlag} parameters allow you to control whether new headers get appended, prepended, or 387 * replace existing headers with the same name. 388 * 389 * <ul class='notes'> 390 * <li>Methods that pass in POJOs convert values to strings using the part serializers. Methods that pass in <c>Header</c> or 391 * <c>NameValuePair</c> objects use the values returned by that bean directly. 392 * </ul> 393 * 394 * 395 * <h4 class='topic'>Request Query Parameters</h4> 396 * <p> 397 * Per-client or per-request query parameters can be specified using the following methods: 398 * <ul class='javatree'> 399 * <li class='jc'>{@link RestClientBuilder} 400 * <ul> 401 * <li class='jm'>{@link RestClientBuilder#query(String,Object) query(String,Object)} 402 * <li class='jm'>{@link RestClientBuilder#query(String,Object,HttpPartSchema) query(String,Object,HttpPartSchema)} 403 * <li class='jm'>{@link RestClientBuilder#query(String,Supplier) query(String,Supplier<?>)} 404 * <li class='jm'>{@link RestClientBuilder#query(String,Supplier,HttpPartSchema) query(String,Supplier<?>,HttpPartSchema)} 405 * <li class='jm'>{@link RestClientBuilder#queries(Object...) queries(Object...)} 406 * <li class='jm'>{@link RestClientBuilder#queryPairs(Object...) queryPairs(Object...)} 407 * </ul> 408 * <li class='jc'>{@link RestRequest} 409 * <ul> 410 * <li class='jm'>{@link RestRequest#query(String,Object) query(String,Object)} 411 * <li class='jm'>{@link RestRequest#query(AddFlag,String,Object) query(AddFlag,String,Object)} 412 * <li class='jm'>{@link RestRequest#queries(Object...) queries(Object...)} 413 * <li class='jm'>{@link RestRequest#queries(AddFlag,Object...) queries(AddFlag,Object...)} 414 * <li class='jm'>{@link RestRequest#queryPairs(Object...) queryPairs(Object...)} 415 * <li class='jm'>{@link RestRequest#queryCustom(Object) queryCustom(Object)} 416 * </ul> 417 * </ul> 418 * 419 * <h5 class='figure'>Example:</h5> 420 * <p class='bcode w800'> 421 * <jc>// Create a client that adds a ?foo=bar query parameter to every request.</jc> 422 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().query(<js>"foo"</js>, <js>"bar"</js>).build(); 423 * 424 * <jc>// Or do it on every request.</jc> 425 * String <jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).query(<js>"foo"</js>, <js>"bar"</js>).run().getBody().asString(); 426 * </p> 427 * 428 * <ul class='notes'> 429 * <li>Like header values, dynamic values and OpenAPI schemas are supported. 430 * <li>Methods that pass in POJOs convert values to strings using the part serializers. Methods that pass in <c>NameValuePair</c> 431 * objects use the values returned by that bean directly. 432 * </ul> 433 * 434 * 435 * <h4 class='topic'>Request Form Data</h4> 436 * 437 * <p class='w900'> 438 * Per-client or per-request form-data parameters can be specified using the following methods: 439 * <ul class='javatree'> 440 * <li class='jc'>{@link RestClientBuilder} 441 * <ul> 442 * <li class='jm'>{@link RestClientBuilder#formData(String,Object) formData(String,Object)} 443 * <li class='jm'>{@link RestClientBuilder#formData(String,Object,HttpPartSchema) formData(String,Object,HttpPartSchema)} 444 * <li class='jm'>{@link RestClientBuilder#formData(String,Supplier) formData(String,Supplier<?>)} 445 * <li class='jm'>{@link RestClientBuilder#formData(String,Supplier,HttpPartSchema) formData(String,Supplier<?>,HttpPartSchema)} 446 * <li class='jm'>{@link RestClientBuilder#formDatas(Object...) formDatas(Object...)} 447 * <li class='jm'>{@link RestClientBuilder#formDataPairs(Object...) formDataPairs(Object...)} 448 * </ul> 449 * <li class='jc'>{@link RestRequest} 450 * <ul> 451 * <li class='jm'>{@link RestRequest#formData(String,Object) formData(String,Object)} 452 * <li class='jm'>{@link RestRequest#formData(AddFlag,String,Object) formData(AddFlag,String,Object)} 453 * <li class='jm'>{@link RestRequest#formDatas(Object...) formDatas(Object...)} 454 * <li class='jm'>{@link RestRequest#formDatas(AddFlag,Object...) formDatas(AddFlag,Object...)} 455 * <li class='jm'>{@link RestRequest#formDataPairs(Object...) formDataPairs(Object...)} 456 * <li class='jm'>{@link RestRequest#formDataCustom(Object) formDataCustom(Object)} 457 * </ul> 458 * </ul> 459 * 460 * <ul class='notes'> 461 * <li>Like header values, dynamic values and OpenAPI schemas are supported. 462 * <li>Methods that pass in POJOs convert values to strings using the part serializers. Methods that pass in <c>NameValuePair</c> 463 * objects use the values returned by that bean directly. 464 * </ul> 465 * 466 * 467 * <h4 class='topic'>Request Body</h4> 468 * 469 * <p class='w900'> 470 * The request body can either be passed in with the client creator method (e.g. {@link RestClient#post(Object,Object) post(uri,body)}), 471 * or can be specified via the following methods: 472 * 473 * <ul class='javatree'> 474 * <li class='jc'>{@link RestRequest} 475 * <ul> 476 * <li class='jm'>{@link RestRequest#body(Object) body(Object)} 477 * <li class='jm'>{@link RestRequest#body(Object,HttpPartSchema) body(Object,HttpPartSchema)} 478 * </ul> 479 * </ul> 480 * 481 * <p class='w900'> 482 * The request body can be any of the following types: 483 * <ul class='javatree'> 484 * <li class='jc'> 485 * {@link Object} - POJO to be converted to text using the {@link Serializer} defined on the client or request. 486 * <li class='jc'> 487 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 488 * <li class='jc'> 489 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 490 * <li class='jc'> 491 * {@link HttpResource}/{@link BasicHttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 492 * <li class='jc'> 493 * {@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 494 * <li class='jc'> 495 * {@link NameValuePairSupplier} - Converted to a URL-encoded FORM post. 496 * <li class='jc'> 497 * {@link Supplier} - A supplier of anything on this list. 498 * </ul> 499 * 500 * <ul class='notes'> 501 * <li>If the serializer on the client or request is explicitly set to <jk>null</jk>, POJOs will be converted to strings 502 * using the registered part serializer as content type <js>"text/plain</js>. If the part serializer is also <jk>null</jk>, 503 * POJOs will be converted to strings using {@link ClassMeta#toString(Object)} which typically just calls {@link Object#toString()}. 504 * </ul> 505 * 506 * 507 * <h4 class='topic'>Response Status</h4> 508 * 509 * <p class='w900'> 510 * After execution using {@link RestRequest#run()} or {@link RestRequest#complete()}, the following methods can be used 511 * to get the response status: 512 * 513 * <ul class='javatree'> 514 * <li class='jc'>{@link RestResponse} 515 * <ul> 516 * <li class='jm'><c>{@link RestResponse#getStatusLine() getStatusLine()} <jk>returns</jk> {@link StatusLine}</c> 517 * <li class='jm'><c>{@link RestResponse#getStatusCode() getStatusCode()} <jk>returns</jk> <jk>int</jk></c> 518 * <li class='jm'><c>{@link RestResponse#getReasonPhrase() getReasonPhrase()} <jk>returns</jk> String</c> 519 * <li class='jm'><c>{@link RestResponse#assertStatus() assertStatus()} <jk>returns</jk> {@link RestResponseStatusLineAssertion}</c> 520 * </ul> 521 * </ul> 522 * 523 * <h5 class='figure'>Example:</h5> 524 * <p class='bcode w800'> 525 * <jc>// Only interested in status code.</jc> 526 * <jk>int</jk> <jv>statusCode</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode(); 527 * </p> 528 * 529 * <p class='w900'> 530 * Equivalent methods with mutable parameters are provided to allow access to status values without breaking fluent call chains. 531 * 532 * <h5 class='figure'>Example:</h5> 533 * <p class='bcode w800'> 534 * <jc>// Interested in multiple values.</jc> 535 * Mutable<Integer> <jv>statusCode</jv> = Mutable.<jsm>create</jsm>(); 536 * Mutable<String> <jv>reasonPhrase</jv> = Mutable.<jsm>create</jsm>(); 537 * 538 * <jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode(<jv>statusCode</jv>).getReasonPhrase(<jv>reasonPhrase</jv>); 539 * System.<jsf>err</jsf>.println(<js>"statusCode="</js>+<jv>statusCode</jv>.get()+<js>", reasonPhrase="</js>+<jv>reasonPhrase</jv>.get()); 540 * </p> 541 * 542 * <ul class='notes'> 543 * <li>If you are only interested in the response status and not the response body, be sure to use {@link RestRequest#complete()} instead 544 * of {@link RestRequest#run()} to make sure the response body gets automatically cleaned up. Otherwise you must 545 * consume the response yourself. 546 * </ul> 547 * 548 * <p class='w900'> 549 * The assertion method is provided for quickly asserting status codes in fluent calls. 550 * 551 * <h5 class='figure'>Example:</h5> 552 * <p class='bcode w800'> 553 * <jc>// Status assertion using a static value.</jc> 554 * String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>) 555 * .run() 556 * .assertStatus().code().isBetween(200,399) 557 * .getBody().asString(); 558 * 559 * <jc>// Status assertion using a predicate.</jc> 560 * String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>) 561 * .run() 562 * .assertStatus().code().passes(<jv>x</jv> -> <jv>x</jv><400) 563 * .getBody().asString(); 564 * </p> 565 * 566 * 567 * <h4 class='topic'>Response Headers</h4> 568 * 569 * <p class='w900'> 570 * Response headers are accessed through the following methods: 571 * 572 * <ul class='javatree'> 573 * <li class='jc'>{@link RestResponse} 574 * <ul> 575 * <li class='jm'><c>{@link RestResponse#getHeader(String) getHeader(String)} <jk>returns</jk> {@link RestResponseHeader}</c> 576 * <li class='jm'><c>{@link RestResponse#getHeaders(String) getHeaders(String)} <jk>returns</jk> {@link RestResponseHeader}[]</c> 577 * <li class='jm'><c>{@link RestResponse#getFirstHeader(String) getFirstHeader(String)} <jk>returns</jk> {@link RestResponseHeader}</c> 578 * <li class='jm'><c>{@link RestResponse#getLastHeader(String) getLastHeader(String)} <jk>returns</jk> {@link RestResponseHeader}</c> 579 * <li class='jm'><c>{@link RestResponse#getAllHeaders() getAllHeaders()} <jk>returns</jk> {@link RestResponseHeader}[]</c> 580 * <li class='jm'><c>{@link RestResponse#getStringHeader(String) getStringHeader(String)} <jk>returns</jk> String</c> 581 * <li class='jm'><c>{@link RestResponse#containsHeader(String) containsHeader(String)} <jk>returns</jk> <jk>boolean</jk></c> 582 * </ul> 583 * </ul> 584 * 585 * <p class='w900'> 586 * Unlike {@link RestResponse#getFirstHeader(String)} and {@link RestResponse#getLastHeader(String)}, the {@link RestResponse#getHeader(String)} 587 * method returns an empty {@link RestResponseHeader} object instead of returning <jk>null</jk>. 588 * This allows it to be used more easily in fluent calls. 589 * 590 * <h5 class='figure'>Example:</h5> 591 * <p class='bcode w800'> 592 * <jc>// See if response contains Location header.</jc> 593 * <jk>boolean</jk> <jv>hasLocationHeader</jv> = client.get(<jsf>URI</jsf>).complete().getHeader(<js>"Location"</js>).exists(); 594 * </p> 595 * 596 * <p class='w900'> 597 * The {@link RestResponseHeader} class extends from the HttpClient {@link Header} class and provides several convenience 598 * methods: 599 * 600 * <ul class='javatree'> 601 * <li class='jc'>{@link RestResponseHeader} 602 * <ul> 603 * <li class='jm'><c>{@link RestResponseHeader#exists() exists()} <jk>returns</jk> <jk>boolean</jk></c> 604 * <li class='jm'><c>{@link RestResponseHeader#asString() asString()} <jk>returns</jk> String</c> 605 * <li class='jm'><c>{@link RestResponseHeader#asOptionalString() asOptionalString()} <jk>returns</jk> Optional<String></c> 606 * <li class='jm'><c>{@link RestResponseHeader#asStringOrElse(String) asStringOrElse(String)} <jk>returns</jk> String</c> 607 * <li class='jm'><c>{@link RestResponseHeader#as(Type,Type...) as(Type,Type...)} <jk>returns</jk> T</c> 608 * <li class='jm'><c>{@link RestResponseHeader#as(Class) as(Class<T>)} <jk>returns</jk> T</c> 609 * <li class='jm'><c>{@link RestResponseHeader#asOptional(Type,Type...) asOptional(Type,Type...)} <jk>returns</jk> Optional<T></c> 610 * <li class='jm'><c>{@link RestResponseHeader#asOptional(Class) asOptional(Class<T>)} <jk>returns</jk> Optional<T></c> 611 * <li class='jm'><c>{@link RestResponseHeader#asMatcher(Pattern) asMatcher(Pattern)} <jk>returns</jk> {@link Matcher}</c> 612 * <li class='jm'><c>{@link RestResponseHeader#asMatcher(String) asMatcher(String)} <jk>returns</jk> {@link Matcher}</c> 613 * <li class='jm'><c>{@link RestResponseHeader#asHeader(Class) asHeader(Class<T <jk>extends</jk> BasicHeader> c)} <jk>returns</jk> {@link BasicHeader}</c> 614 * <li class='jm'><c>{@link RestResponseHeader#asStringHeader() asStringHeader()} <jk>returns</jk> {@link BasicIntegerHeader}</c> 615 * <li class='jm'><c>{@link RestResponseHeader#asIntegerHeader() asIntegerHeader()} <jk>returns</jk> {@link BasicStringHeader}</c> 616 * <li class='jm'><c>{@link RestResponseHeader#asLongHeader() asLongHeader()} <jk>returns</jk> {@link BasicLongHeader}</c> 617 * <li class='jm'><c>{@link RestResponseHeader#asDateHeader() asDateHeader()} <jk>returns</jk> {@link BasicDateHeader}</c> 618 * <li class='jm'><c>{@link RestResponseHeader#asCsvArrayHeader() asCsvArrayHeader()} <jk>returns</jk> {@link BasicCsvArrayHeader}</c> 619 * <li class='jm'><c>{@link RestResponseHeader#asEntityTagArrayHeader() asEntityValidatorArrayHeader()} <jk>returns</jk> {@link BasicEntityTagArrayHeader}</c> 620 * <li class='jm'><c>{@link RestResponseHeader#asStringRangeArrayHeader() asRangeArrayHeader()} <jk>returns</jk> {@link BasicStringRangeArrayHeader}</c> 621 * <li class='jm'><c>{@link RestResponseHeader#asUriHeader() asUriHeader()} <jk>returns</jk> {@link BasicUriHeader}</c> 622 * </ul> 623 * </ul> 624 * 625 * <p> 626 * The {@link RestResponseHeader#schema(HttpPartSchema)} method allows you to perform parsing of OpenAPI formats for 627 * header parts. 628 * 629 * <h5 class='figure'>Example:</h5> 630 * <p class='bcode w800'> 631 * <jc>// Parse the header "Foo: bar|baz".</jc> 632 * List<String> <jv>fooHeader</jv> = <jv>client</jv> 633 * .get(<jsf>URI</jsf>) 634 * .complete() 635 * .getHeader(<js>"Foo"</js>).schema(<jsf>T_ARRAY_PIPES</jsf>).as(List.<jk>class</jk>, String.<jk>class</jk>); 636 * </p> 637 * 638 * <p> 639 * Assertion methods are also provided for fluent-style calls: 640 * 641 * <ul class='javatree'> 642 * <li class='jc'>{@link RestResponseHeader} 643 * <ul> 644 * <li class='jm'><c>{@link RestResponseHeader#assertString() assertString()} <jk>returns</jk> {@link FluentStringAssertion}</c> 645 * <li class='jm'><c>{@link RestResponseHeader#assertInteger() assertInteger()} <jk>returns</jk> {@link FluentIntegerAssertion}</c> 646 * <li class='jm'><c>{@link RestResponseHeader#assertLong() assertLong()} <jk>returns</jk> {@link FluentLongAssertion}</c> 647 * <li class='jm'><c>{@link RestResponseHeader#assertDate() assertDate()} <jk>returns</jk> {@link FluentDateAssertion}</c> 648 * </ul> 649 * </ul> 650 * 651 * <p> 652 * Note how in the following example, the fluent assertion returns control to the {@link RestResponse} object after 653 * the assertion has been completed: 654 * 655 * <h5 class='figure'>Example:</h5> 656 * <p class='bcode w800'> 657 * <jc>// Assert the response content type is any sort of JSON.</jc> 658 * String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>) 659 * .run() 660 * .getHeader(<js>"Content-Type"</js>).assertString().matchesSimple(<js>"application/json*"</js>) 661 * .getBody().asString(); 662 * </p> 663 * 664 * 665 * <h4 class='topic'>Response Body</h4> 666 * 667 * <p class='w900'> 668 * The response body is accessed through the following method: 669 * 670 * <ul class='javatree'> 671 * <li class='jc'>{@link RestResponse} 672 * <ul> 673 * <li class='jm'><c>{@link RestResponse#getBody() getBody()} <jk>returns</jk> {@link RestResponseBody}</c> 674 * </ul> 675 * </ul> 676 * 677 * <p class='w900'> 678 * The {@link RestResponseBody} class extends from the HttpClient {@link HttpEntity} class and provides several convenience 679 * methods: 680 * 681 * <ul class='javatree'> 682 * <li class='jc'>{@link RestResponseBody} 683 * <ul> 684 * <li class='jm'><c>{@link RestResponseBody#asInputStream() asInputStream()} <jk>returns</jk> InputStream</c> 685 * <li class='jm'><c>{@link RestResponseBody#asReader() asReader()} <jk>returns</jk> Reader</c> 686 * <li class='jm'><c>{@link RestResponseBody#asReader(Charset) asReader(Charset)} <jk>returns</jk> Reader</c> 687 * <li class='jm'><c>{@link RestResponseBody#pipeTo(OutputStream) pipeTo(OutputStream)} <jk>returns</jk> {@link RestResponse}</c> 688 * <li class='jm'><c>{@link RestResponseBody#pipeTo(Writer) pipeTo(Writer)} <jk>returns</jk> {@link RestResponse}</c> 689 * <li class='jm'><c>{@link RestResponseBody#as(Type,Type...) as(Type,Type...)} <jk>returns</jk> T</c> 690 * <li class='jm'><c>{@link RestResponseBody#as(Class) as(Class<T>)} <jk>returns</jk> T</c> 691 * <li class='jm'><c>{@link RestResponseBody#asFuture(Class) asFuture(Class<T>)} <jk>returns</jk> Future<T></c> 692 * <li class='jm'><c>{@link RestResponseBody#asFuture(Type,Type...) asFuture(Type,Type...)} <jk>returns</jk> Future<T></c> 693 * <li class='jm'><c>{@link RestResponseBody#asString() asString()} <jk>returns</jk> String</c> 694 * <li class='jm'><c>{@link RestResponseBody#asStringFuture() asStringFuture()} <jk>returns</jk> Future<String></c> 695 * <li class='jm'><c>{@link RestResponseBody#asAbbreviatedString(int) asAbbreviatedString(int)} <jk>returns</jk> String</c> 696 * <li class='jm'><c>{@link RestResponseBody#asPojoRest(Class) asPojoRest(Class<?>)} <jk>returns</jk> {@link PojoRest}</c> 697 * <li class='jm'><c>{@link RestResponseBody#asPojoRest() asPojoRest()} <jk>returns</jk> {@link PojoRest}</c> 698 * <li class='jm'><c>{@link RestResponseBody#asMatcher(Pattern) asMatcher(Pattern)} <jk>returns</jk> {@link Matcher}</c> 699 * <li class='jm'><c>{@link RestResponseBody#asMatcher(String) asMatcher(String)} <jk>returns</jk> {@link Matcher}</c> 700 * </ul> 701 * </ul> 702 * 703 * <br> 704 * 705 * <h5 class='figure'>Examples:</h5> 706 * <p class='bcode w800'> 707 * <jc>// Parse into a linked-list of strings.</jc> 708 * List<String> <jv>l1</jv> = <jv>client</jv> 709 * .get(<jsf>URI</jsf>) 710 * .run() 711 * .getBody().as(LinkedList.<jk>class</jk>, String.<jk>class</jk>); 712 * 713 * <jc>// Parse into a linked-list of beans.</jc> 714 * List<MyBean> <jv>l2</jv> = <jv>client</jv> 715 * .get(<jsf>URI</jsf>) 716 * .run() 717 * .getBody().as(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>); 718 * 719 * <jc>// Parse into a linked-list of linked-lists of strings.</jc> 720 * List<List<String>> <jv>l3</jv> = <jv>client</jv> 721 * .get(<jsf>URI</jsf>) 722 * .run() 723 * .getBody().as(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>); 724 * 725 * <jc>// Parse into a map of string keys/values.</jc> 726 * Map<String,String> <jv>m1</jv> = <jv>client</jv> 727 * .get(<jsf>URI</jsf>) 728 * .run() 729 * .getBody().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>); 730 * 731 * <jc>// Parse into a map containing string keys and values of lists containing beans.</jc> 732 * Map<String,List<MyBean>> <jv>m2<jv> = <jv>client</jv> 733 * .get(<jsf>URI</jsf>) 734 * .run() 735 * .getBody().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>); 736 * </p> 737 * 738 * <p class='w900'> 739 * The response body can only be consumed once unless it has been cached into memory. In many cases, the body is 740 * automatically cached when using the assertions methods or methods such as {@link RestResponseBody#asString()}. 741 * However, methods that involve reading directly from the input stream cannot be called twice. 742 * In these cases, the {@link RestResponse#cacheBody()} and {@link RestResponseBody#cache()} methods are provided 743 * to cache the response body in memory so that you can perform several operations against it. 744 * 745 * <p class='bcode w800'> 746 * <jc>// Cache the response body so we can access it twice.</jc> 747 * InputStream <jv>inputStream</jv> = <jv>client</jv> 748 * .get(<jsf>URI</jsf>) 749 * .run() 750 * .cacheBody() 751 * .getBody().pipeTo(<jv>someOtherStream</jv>) 752 * .getBody().asInputStream(); 753 * </p> 754 * 755 * <p> 756 * Assertion methods are also provided for fluent-style calls: 757 * 758 * <ul class='javatree'> 759 * <li class='jc'>{@link RestResponseBody} 760 * <ul> 761 * <li class='jm'><c>{@link RestResponseBody#assertString() assertString()} <jk>returns</jk> {@link FluentStringAssertion}</c> 762 * <li class='jm'><c>{@link RestResponseBody#assertObject(Class) assertObject(Class<?>)} <jk>returns</jk> {@link FluentObjectAssertion}</c> 763 * <li class='jm'><c>{@link RestResponseBody#assertBytes() assertBytes()} <jk>returns</jk> {@link FluentByteArrayAssertion}</c> 764 * </ul> 765 * </ul> 766 * 767 * <br> 768 * 769 * <h5 class='figure'>Example:</h5> 770 * <p class='bcode w800'> 771 * <jc>// Assert that the body contains the string "Success".</jc> 772 * String <jv>body</jv> = <jv>client</jv> 773 * .get(<jsf>URI</jsf>) 774 * .run() 775 * .getBody().assertString().contains(<js>"Success"</js>) 776 * .getBody().asString(); 777 * </p> 778 * 779 * <p> 780 * Object assertions allow you to parse the response body into a POJO and then perform various tests on that resulting 781 * POJO. 782 * 783 * <h5 class='figure'>Example:</h5> 784 * <p class='bcode w800'> 785 * <jc>// Parse bean into POJO and then validate that it was parsed correctly.</jc> 786 * MyBean <jv>bean</jv> = <jv>client</jv>.get(<jsf>URI</jsf>) 787 * .run() 788 * .getBody().assertObject(MyBean.<jk>class</jk>).json().is(<js>"{foo:'bar'}"</js>) 789 * .getBody().as(MyBean.<jk>class</jk>); 790 * </p> 791 * 792 * 793 * <h4 class='topic'>Custom Call Handlers</h4> 794 * 795 * <p class='w900'> 796 * The {@link RestCallHandler} interface provides the ability to provide custom handling of requests. 797 * 798 * <ul class='javatree'> 799 * <li class='jc'>{@link RestClientBuilder} 800 * <ul> 801 * <li class='jm'>{@link RestClientBuilder#callHandler(Class) callHandler(Class<? extends RestCallHandler>)} 802 * <li class='jm'>{@link RestClientBuilder#callHandler(RestCallHandler) callHandler(RestCallHandler)} 803 * </ul> 804 * <li class='jic'>{@link RestCallHandler} 805 * <ul> 806 * <li class='jm'><c>{@link RestCallHandler#run(HttpHost,HttpRequest,HttpContext) run(HttpHost,HttpRequest,HttpContext)} <jk>returns</jk> HttpResponse</c> 807 * </ul> 808 * </ul> 809 * 810 * <p class='w900'> 811 * Note that there are other ways of accomplishing this such as extending the {@link RestClient} class and overriding 812 * the {@link #run(HttpHost,HttpRequest,HttpContext)} method 813 * or by defining your own {@link HttpRequestExecutor}. Using this interface is often simpler though. 814 * 815 * 816 * <h4 class='topic'>Interceptors</h4> 817 * 818 * <p class='w900'> 819 * The {@link RestCallInterceptor} API provides a quick way of intercepting and manipulating requests and responses beyond 820 * the existing {@link HttpRequestInterceptor} and {@link HttpResponseInterceptor} APIs. 821 * 822 * <ul class='javatree'> 823 * <li class='jc'>{@link RestClientBuilder} 824 * <ul> 825 * <li class='jm'>{@link RestClientBuilder#interceptors(Object...) interceptors(Object...)} 826 * </ul> 827 * <li class='jc'>{@link RestRequest} 828 * <ul> 829 * <li class='jm'>{@link RestRequest#interceptors(RestCallInterceptor...) interceptors(RestCallInterceptor...)} 830 * </ul> 831 * <li class='jic'>{@link RestCallInterceptor} 832 * <ul> 833 * <li class='jm'>{@link RestCallInterceptor#onInit(RestRequest) onInit(RestRequest)} 834 * <li class='jm'>{@link RestCallInterceptor#onConnect(RestRequest,RestResponse) onConnect(RestRequest,RestResponse)} 835 * <li class='jm'>{@link RestCallInterceptor#onClose(RestRequest,RestResponse) onClose(RestRequest,RestResponse)} 836 * </ul> 837 * </ul> 838 * 839 * 840 * <h4 class='topic'>Logging / Debugging</h4> 841 * 842 * <p class='w900'> 843 * The following methods provide logging of requests and responses: 844 * 845 * <ul class='javatree'> 846 * <li class='jc'>{@link RestClientBuilder} 847 * <ul> 848 * <li class='jm'>{@link RestClientBuilder#logger(Logger) logger(Logger)} 849 * <li class='jm'>{@link RestClientBuilder#logToConsole() logToConsole()} 850 * <li class='jm'>{@link RestClientBuilder#logRequests(DetailLevel,Level,BiPredicate) logRequests(DetailLevel,Level,BiPredicate)} 851 * </ul> 852 * </ul> 853 * 854 * <p> 855 * The following example shows the results of logging all requests that end with <c>/bean</c>. 856 * 857 * <h5 class='figure'>Examples:</h5> 858 * <p class='bcode w800'> 859 * MyBean <jv>bean</jv> = RestClient 860 * .<jsm>create</jsm>() 861 * .simpleJson() 862 * .logRequests(DetailLevel.<jsf>FULL</jsf>, Level.<jsf>SEVERE</jsf>, (<jv>req</jv>,<jv>res</jv>)-><jv>req</jv>.getUri().endsWith(<js>"/bean"</js>)) 863 * .logToConsole() 864 * .build() 865 * .post(<js>"http://localhost/bean"</js>, <jv>anotherBean</jv>) 866 * .run() 867 * .getBody().as(MyBean.<jk>class</jk>); 868 * </p> 869 * 870 * <p> 871 * This produces the following console output: 872 * 873 * <p class='bcode w800 console'> 874 * === HTTP Call (outgoing) ====================================================== 875 * === REQUEST === 876 * POST http://localhost/bean 877 * ---request headers--- 878 * Accept: application/json+simple 879 * ---request entity--- 880 * Content-Type: application/json+simple 881 * ---request content--- 882 * {f:1} 883 * === RESPONSE === 884 * HTTP/1.1 200 885 * ---response headers--- 886 * Content-Type: application/json 887 * ---response content--- 888 * {f:1} 889 * === END =======================================================================", 890 * </p> 891 * 892 * 893 * <p class='notes w900'> 894 * It should be noted that if you enable request logging detail level {@link DetailLevel#FULL}, response bodies will be cached by default which may introduce 895 * a performance penalty. 896 * 897 * <p class='w900'> 898 * Additionally, the following method is also provided for enabling debug mode: 899 * 900 * <ul class='javatree'> 901 * <li class='jc'>{@link RestClientBuilder} 902 * <ul> 903 * <li class='jm'>{@link RestClientBuilder#debug() debug()} 904 * </ul> 905 * </ul> 906 * 907 * <p class='w900'> 908 * Enabling debug mode has the following effects: 909 * <ul> 910 * <li>{@link Context#CONTEXT_debug} is enabled. 911 * <li>{@link #RESTCLIENT_leakDetection} is enabled. 912 * <li>{@link RestClientBuilder#logToConsole()} is called. 913 * </ul> 914 * 915 * 916 * <h4 class='topic'>REST Proxies</h4> 917 * 918 * <p class='w900'> 919 * One of the more powerful features of the REST client class is the ability to produce Java interface proxies against 920 * arbitrary remote REST resources. 921 * 922 * <h5 class='figure'>Example:</h5> 923 * <p class='bcode w800'> 924 * <jc>// Define a Remote proxy for interacting with a REST interface.</jc> 925 * <ja>@Remote</ja>(path=<js>"/petstore"</js>) 926 * <jk>public interface</jk> PetStore { 927 * 928 * <ja>@RemoteMethod</ja>(httpMethod=<jsf>POST</jsf>, path=<js>"/pets"</js>) 929 * Pet addPet( 930 * <ja>@Body</ja> CreatePet <jv>pet</jv>, 931 * <ja>@Header</ja>(<js>"E-Tag"</js>) UUID <jv>etag</jv>, 932 * <ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> <jv>debug</jv> 933 * ); 934 * } 935 * 936 * <jc>// Use a RestClient with default Simple JSON support.</jc> 937 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build()) 938 * 939 * PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>); 940 * CreatePet <jv>createPet</jv> = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99); 941 * Pet <jv>pet</jv> = <jv>store</jv>.addPet(<jv>createPet</jv>, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>); 942 * </p> 943 * 944 * <p class='w900'> 945 * The methods to retrieve remote interfaces are: 946 * 947 * <ul class='javatree'> 948 * <li class='jc'>{@link RestClient} 949 * <ul> 950 * <li class='jm'><c>{@link RestClient#getRemote(Class) getRemote(Class<T>)} <jk>returns</jk> T</c> 951 * <li class='jm'><c>{@link RestClient#getRemote(Class,Object) getRemote(Class<T>,Object)} <jk>returns</jk> T</c> 952 * <li class='jm'><c>{@link RestClient#getRemote(Class,Object,Serializer,Parser) getRemote(Class<T>,Object,Serializer,Parser)} <jk>returns</jk> T</c> 953 * <li class='jm'><c>{@link RestClient#getRrpcInterface(Class) getRrpcInterface(Class<T>)} <jk>returns</jk> T</c> 954 * <li class='jm'><c>{@link RestClient#getRrpcInterface(Class,Object) getRrpcInterface(Class<T>,Object)} <jk>returns</jk> T</c> 955 * <li class='jm'><c>{@link RestClient#getRrpcInterface(Class,Object,Serializer,Parser) getRrpcInterface(Class<T>,Object,Serializer,Parser)} <jk>returns</jk> T</c> 956 * </ul> 957 * </ul> 958 * 959 * <p class='w900'> 960 * Two basic types of remote interfaces are provided: 961 * 962 * <ul class='spaced-list'> 963 * <li>{@link Remote @Remote}-annotated interfaces. These can be defined against arbitrary external REST resources. 964 * <li>RPC-over-REST interfaces. These are Java interfaces that allow you to make method calls on server-side POJOs. 965 * </ul> 966 * 967 * <p class='w900'> 968 * Refer to the following documentation on both flavors: 969 * 970 * <ul class='doctree'> 971 * <li class='link'>{@doc RestcProxies} 972 * <li class='link'>{@doc RestRpc} 973 * </ul> 974 * 975 * <br> 976 * <hr class='w900'> 977 * <h4 class='topic'>Customizing Apache HttpClient</h4> 978 * 979 * <p class='w900'> 980 * Several methods are provided for customizing the underlying HTTP client and client builder classes: 981 * <ul class='javatree'> 982 * <li class='jc'>{@link RestClientBuilder} 983 * <ul> 984 * <li class='jm'>{@link RestClientBuilder#httpClientBuilder(HttpClientBuilder) httpClientBuilder(HttpClientBuilder)} - Set the client builder yourself. 985 * <li class='jm'>{@link RestClientBuilder#createHttpClientBuilder() createHttpClientBuilder()} - Override to create the client builder. 986 * <li class='jm'>{@link RestClientBuilder#createHttpClient() createHttpClient()} - Override to create the client. 987 * <li class='jm'>{@link RestClientBuilder#createConnectionManager() createConnectionManager()} - Override to create the connection management. 988 * </ul> 989 * </ul> 990 * 991 * <p class='w900'> 992 * Additionally, all methods on the <c>HttpClientBuilder</c> class have been extended with fluent setters. 993 * 994 * <h5 class='figure'>Example:</h5> 995 * <p class='bcode w800'> 996 * <jc>// Create a client with customized HttpClient settings.</jc> 997 * MyBean <jv>bean</jv> = RestClient 998 * .<jsm>create</jsm>() 999 * .disableRedirectHandling() 1000 * .connectionManager(<jv>myConnectionManager</jv>) 1001 * .addInterceptorFirst(<jv>myHttpRequestInterceptor</jv>) 1002 * .build(); 1003 * </p> 1004 * 1005 * <p> 1006 * Refer to the {@link HttpClientBuilder HTTP Client Builder API} for more information. 1007 * 1008 * 1009 * <h4 class='topic'>Extending RestClient</h4> 1010 * 1011 * <p class='w900'> 1012 * The <c>RestClient</c> API has been designed to allow for the ability to be easily extended. 1013 * The following example that overrides the primary run method shows how this can be done. 1014 * 1015 * <h5 class='figure'>Example:</h5> 1016 * <p class='bcode w800'> 1017 * <jk>public class</jk> MyRestClient <jk>extends</jk> RestClient { 1018 * 1019 * <jc>// Must provide this constructor!</jc> 1020 * <jk>public</jk> MyRestClient(PropertyStore <jv>ps</jv>) { 1021 * <jk>super</jk>(<jv>ps</jv>); 1022 * } 1023 * 1024 * <ja>@Override</ja> 1025 * <jk>public</jk> HttpResponse run(HttpHost <jv>target</jv>, HttpRequest <jv>request</jv>, HttpContext <jv>context</jv>) <jk>throws</jk> IOException { 1026 * <jc>// Perform special handling of requests.</jc> 1027 * } 1028 * } 1029 * 1030 * <jc>// Instantiate your client.</jc> 1031 * MyRestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().build(MyRestClient.<jk>class</jk>); 1032 * </p> 1033 * 1034 * <p class='w900'> 1035 * The {@link RestRequest} and {@link RestResponse} objects can also be extended and integrated by overriding the 1036 * {@link RestClient#createRequest(URI, String, boolean)} and {@link RestClient#createResponse(RestRequest, HttpResponse, Parser)} methods. 1037 * 1038 * 1039 * <ul class='seealso'> 1040 * <li class='link'>{@doc juneau-rest-client} 1041 * </ul> 1042 */ 1043@ConfigurableContext(nocache=true) 1044public class RestClient extends BeanContext implements HttpClient, Closeable, RestCallHandler, RestCallInterceptor { 1045 1046 //------------------------------------------------------------------------------------------------------------------- 1047 // Configurable properties 1048 //------------------------------------------------------------------------------------------------------------------- 1049 1050 private static final String PREFIX = "RestClient."; 1051 1052 /** 1053 * Configuration property: REST call handler. 1054 * 1055 * <h5 class='section'>Property:</h5> 1056 * <ul class='spaced-list'> 1057 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_callHandler RESTCLIENT_callHandler} 1058 * <li><b>Name:</b> <js>"RestClient.callHandler.o"</js> 1059 * <li><b>Data type:</b> 1060 * <ul> 1061 * <li><c>Class<? <jk>extends</jk> {@link org.apache.juneau.rest.client2.RestCallHandler}></c> 1062 * <li>{@link org.apache.juneau.rest.client2.RestCallHandler} 1063 * </ul> 1064 * <li><b>Default:</b> <c><jk>null</jk></c> 1065 * <li><b>Methods:</b> 1066 * <ul> 1067 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#callHandler(Class)} 1068 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#callHandler(RestCallHandler)} 1069 * </ul> 1070 * </ul> 1071 * 1072 * <h5 class='section'>Description:</h5> 1073 * 1074 * <p> 1075 * Allows you to provide a custom handler for making HTTP calls. 1076 * 1077 * <h5 class='section'>Example:</h5> 1078 * <p class='bcode w800'> 1079 * <jc>// Create a client that handles processing of requests using a custom handler.</jc> 1080 * RestClient <jv>client</jv> = RestClient 1081 * .<jsm>create</jsm>() 1082 * .callHandler( 1083 * <jk>new</jk> RestCallHandler() { 1084 * <ja>@Override</ja> 1085 * <jk>public</jk> HttpResponse run(HttpHost <jv>target</jv>, HttpRequest <jv>request</jv>, HttpContext <jv>context</jv>) <jk>throws</jk> IOException { 1086 * <jc>// Custom handle requests.</jc> 1087 * } 1088 * } 1089 * ) 1090 * .build(); 1091 * </p> 1092 */ 1093 public static final String RESTCLIENT_callHandler = PREFIX + "callHandler.o"; 1094 1095 /** 1096 * Configuration property: Console print stream. 1097 * 1098 * <h5 class='section'>Property:</h5> 1099 * <ul class='spaced-list'> 1100 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_console RESTCLIENT_console} 1101 * <li><b>Name:</b> <js>"RestClient.console.o"</js> 1102 * <li><b>System property:</b> <c>RestClient.console</c> 1103 * <li><b>Data type:</b> 1104 * <ul> 1105 * <li><b>Data type:</b> <c>Class<? <jk>extends</jk> {@link java.io.PrintStream}> | {@link java.io.PrintStream}</c> 1106 * </ul> 1107 * <li><b>Default:</b> <c>System.<jsf>out</jsf></c> 1108 * <li><b>Methods:</b> 1109 * <ul> 1110 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#console(PrintStream)} 1111 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#console(Class)} 1112 * </ul> 1113 * </ul> 1114 * 1115 * <h5 class='section'>Description:</h5> 1116 * <p> 1117 * Allows you to redirect the console output to a different print stream. 1118 */ 1119 public static final String RESTCLIENT_console = PREFIX + "console.o"; 1120 1121 /** 1122 * Configuration property: Error codes predicate. 1123 * 1124 * <h5 class='section'>Property:</h5> 1125 * <ul class='spaced-list'> 1126 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_errorCodes RESTCLIENT_errorCodes} 1127 * <li><b>Name:</b> <js>"RestClient.errorCodes.o"</js> 1128 * <li><b>Data type:</b> {@link java.util.function.Predicate}<{@link java.lang.Integer}> 1129 * <li><b>Default:</b> <code>x -> x>=400</code> 1130 * <li><b>Methods:</b> 1131 * <ul> 1132 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#errorCodes(Predicate)} 1133 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#errorCodes(Predicate)} 1134 * </ul> 1135 * </ul> 1136 * 1137 * <h5 class='section'>Description:</h5> 1138 * 1139 * <p> 1140 * Defines a predicate to test for error codes. 1141 * 1142 * <h5 class='section'>Example:</h5> 1143 * <p class='bcode w800'> 1144 * <jc>// Create a client that considers any 300+ responses to be errors.</jc> 1145 * RestClient <jv>client</jv> = RestClient 1146 * .<jsm>create</jsm>() 1147 * .errorCodes(<jv>x</jv> -> <jv>x</jv> >= 300) 1148 * .build(); 1149 * </p> 1150 */ 1151 public static final String RESTCLIENT_errorCodes = PREFIX + "errorCodes.o"; 1152 1153 /** 1154 * Configuration property: Executor service. 1155 * 1156 * <h5 class='section'>Property:</h5> 1157 * <ul class='spaced-list'> 1158 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_executorService RESTCLIENT_executorService} 1159 * <li><b>Name:</b> <js>"RestClient.executorService.o"</js> 1160 * <li><b>Data type:</b> 1161 * <ul> 1162 * <li><c>Class<? <jk>extends</jk> {@link java.util.concurrent.ExecutorService}></c> 1163 * <li>{@link java.util.concurrent.ExecutorService} 1164 * </ul> 1165 * <li><b>Default:</b> <jk>null</jk>. 1166 * <li><b>Methods:</b> 1167 * <ul> 1168 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#executorService(ExecutorService, boolean)} 1169 * </ul> 1170 * </ul> 1171 * 1172 * <h5 class='section'>Description:</h5> 1173 * <p> 1174 * Defines the executor service to use when calling future methods on the {@link RestRequest} class. 1175 * 1176 * <p> 1177 * This executor service is used to create {@link Future} objects on the following methods: 1178 * <ul> 1179 * <li class='jm'>{@link RestRequest#runFuture()} 1180 * <li class='jm'>{@link RestRequest#completeFuture()} 1181 * <li class='jm'>{@link RestResponseBody#asFuture(Class)} (and similar methods) 1182 * </ul> 1183 * 1184 * <p> 1185 * The default executor service is a single-threaded {@link ThreadPoolExecutor} with a 30 second timeout 1186 * and a queue size of 10. 1187 * 1188 * <h5 class='section'>Example:</h5> 1189 * <p class='bcode w800'> 1190 * <jc>// Create a client with a customized executor service.</jc> 1191 * RestClient <jv>client</jv> = RestClient 1192 * .<jsm>create</jsm>() 1193 * .executorService(<jk>new</jk> ThreadPoolExecutor(1, 1, 30, TimeUnit.<jsf>SECONDS</jsf>, <jk>new</jk> ArrayBlockingQueue<Runnable>(10)), <jk>true</jk>) 1194 * .build(); 1195 * 1196 * <jc>// Use it to asynchronously run a request.</jc> 1197 * Future<RestResponse> <jv>responseFuture</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).runFuture(); 1198 * 1199 * <jc>// Do some other stuff.</jc> 1200 * 1201 * <jc>// Now read the response.</jc> 1202 * String <jv>body</jv> = <jv>responseFuture</jv>.get().getBody().asString(); 1203 * 1204 * <jc>// Use it to asynchronously retrieve a response.</jc> 1205 * Future<MyBean> <jv>myBeanFuture</jv> = <jv>client</jv> 1206 * .get(<jsf>URI</jsf>) 1207 * .run() 1208 * .getBody().asFuture(MyBean.<jk>class</jk>); 1209 * 1210 * <jc>// Do some other stuff.</jc> 1211 * 1212 * <jc>// Now read the response.</jc> 1213 * MyBean <jv>bean</jv> = <jv>myBeanFuture</jv>.get(); 1214 * </p> 1215 */ 1216 public static final String RESTCLIENT_executorService = PREFIX + "executorService.o"; 1217 1218 /** 1219 * Configuration property: Shut down executor service on close. 1220 * 1221 * <h5 class='section'>Property:</h5> 1222 * <ul class='spaced-list'> 1223 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_executorServiceShutdownOnClose RESTCLIENT_executorServiceShutdownOnClose} 1224 * <li><b>Name:</b> <js>"RestClient.executorServiceShutdownOnClose.b"</js> 1225 * <li><b>Data type:</b> <jk>boolean</jk> 1226 * <li><b>System property:</b> <c>RestClient.executorServiceShutdownOnClose</c> 1227 * <li><b>Environment variable:</b> <c>RESTCLIENT_EXECUTORSERVICESHUTDOWNONCLOSE</c> 1228 * <li><b>Default:</b> <jk>false</jk> 1229 * <li><b>Methods:</b> 1230 * <ul> 1231 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#executorService(ExecutorService, boolean)} 1232 * </ul> 1233 * </ul> 1234 * 1235 * <h5 class='section'>Description:</h5> 1236 * <p> 1237 * Call {@link ExecutorService#shutdown()} when {@link RestClient#close()} is called. 1238 */ 1239 public static final String RESTCLIENT_executorServiceShutdownOnClose = PREFIX + "executorServiceShutdownOnClose.b"; 1240 1241 /** 1242 * Configuration property: Request form-data parameters. 1243 * 1244 * <h5 class='section'>Property:</h5> 1245 * <ul class='spaced-list'> 1246 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_formData RESTCLIENT_formData} 1247 * <li><b>Name:</b> <js>"RestClient.formData.lo"</js> 1248 * <li><b>Data type:</b> <c>List<{@link org.apache.http.NameValuePair}></c> 1249 * <li><b>Default:</b> empty map 1250 * <li><b>Methods:</b> 1251 * <ul> 1252 * <li class='jc'>{@link org.apache.juneau.rest.client2.RestClientBuilder} 1253 * <ul> 1254 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#formData(String,Object) formData(String,Object)} 1255 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#formData(String,Object,HttpPartSchema,HttpPartSerializer) formData(String,Object,HttpPartSerializer,HttpPartSchema)} 1256 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#formDatas(Object...) formDatas(Object...)} 1257 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#formDataPairs(Object...) formDataPairs(Map<String, Object>)} 1258 * </ul> 1259 * <li class='jc'>{@link org.apache.juneau.rest.client2.RestRequest} 1260 * <ul> 1261 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formData(String,Object) formData(String,Object)} 1262 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formData(AddFlag,String,Object) formData(EnumSet<AddFlag>,String,Object)} 1263 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formDatas(Object...) formDatas(Object...)} 1264 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formDatas(AddFlag,Object...) formDatas(EnumSet<AddFlag>Object...)} 1265 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formDataPairs(Object...) formDataPairs(Object...)} 1266 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formDataCustom(Object) formDataCustom(Object)} 1267 * </ul> 1268 * </ul> 1269 * </ul> 1270 * 1271 * <h5 class='section'>Description:</h5> 1272 * <p> 1273 * Query parameters to add to every request. 1274 */ 1275 public static final String RESTCLIENT_formData = PREFIX + "formData.lo"; 1276 1277 /** 1278 * Configuration property: Request headers. 1279 * 1280 * <h5 class='section'>Property:</h5> 1281 * <ul class='spaced-list'> 1282 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_headers RESTCLIENT_headers} 1283 * <li><b>Name:</b> <js>"RestClient.headers.lo"</js> 1284 * <li><b>Data type:</b> <c>List<{@link org.apache.http.Header} | {@link org.apache.http.NameValuePair}></c> 1285 * <li><b>Default:</b> empty map 1286 * <li><b>Methods:</b> 1287 * <ul> 1288 * <li class='jc'>{@link org.apache.juneau.rest.client2.RestClientBuilder} 1289 * <ul> 1290 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#header(String,Object) header(String,Object)} 1291 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#header(String,Object,HttpPartSchema,HttpPartSerializer) header(String,Object,HttpPartSerializer,HttpPartSchema)} 1292 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#header(Header) header(Header)} 1293 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#headers(Object...) headers(Object...)} 1294 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#headerPairs(Object...) headerPairs(Object...)} 1295 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#accept(Object) accept(Object)} 1296 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#acceptCharset(Object) acceptCharset(Object)} 1297 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#acceptEncoding(Object) acceptEncoding(Object)} 1298 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#acceptLanguage(Object) acceptLanguage(Object)} 1299 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#authorization(Object) authorization(Object)} 1300 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#cacheControl(Object) cacheControl(Object)} 1301 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#clientVersion(Object) clientVersion(Object)} 1302 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#connection(Object) connection(Object)} 1303 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#contentLength(Object) contentLength(Object)} 1304 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#contentType(Object) contentType(Object)} 1305 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#date(Object) date(Object)} 1306 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#expect(Object) expect(Object)} 1307 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#forwarded(Object) forwarded(Object)} 1308 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#from(Object) from(Object)} 1309 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#host(Object) host(Object)} 1310 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#ifMatch(Object) ifMatch(Object)} 1311 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#ifModifiedSince(Object) ifModifiedSince(Object)} 1312 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#ifNoneMatch(Object) ifNoneMatch(Object)} 1313 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#ifRange(Object) ifRange(Object)} 1314 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#ifUnmodifiedSince(Object) ifUnmodifiedSince(Object)} 1315 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#maxForwards(Object) maxForwards(Object)} 1316 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#origin(Object) origin(Object)} 1317 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#pragma(Object) pragma(Object)} 1318 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#proxyAuthorization(Object) proxyAuthorization(Object)} 1319 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#range(Object) proxyAuthorization(Object)} 1320 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#referer(Object) referer(Object)} 1321 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#te(Object) te(Object)} 1322 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#userAgent(Object) userAgent(Object)} 1323 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#upgrade(Object) upgrade(Object)} 1324 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#via(Object) via(Object)} 1325 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#warning(Object) warning(Object)} 1326 * </ul> 1327 * <li class='jc'>{@link org.apache.juneau.rest.client2.RestRequest} 1328 * <ul> 1329 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#header(String,Object) header(String,Object)} 1330 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#header(AddFlag,String,Object) header(EnumSet>AddFlag>,String,Object)} 1331 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#header(Header) header(Header)} 1332 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#headers(Object...) headers(Object...)} 1333 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#headers(AddFlag,Object...) headers(EnumSet>AddFlag>,Object...)} 1334 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#headerPairs(Object...) headerPairs(Object...)} 1335 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#accept(Object) accept(Object)} 1336 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#acceptCharset(Object) acceptCharset(Object)} 1337 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#acceptEncoding(Object) acceptEncoding(Object)} 1338 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#acceptLanguage(Object) acceptLanguage(Object)} 1339 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#authorization(Object) authorization(Object)} 1340 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#cacheControl(Object) cacheControl(Object)} 1341 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#clientVersion(Object) clientVersion(Object)} 1342 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#connection(Object) connection(Object)} 1343 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#contentLength(Object) contentLength(Object)} 1344 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#contentType(Object) contentType(Object)} 1345 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#date(Object) date(Object)} 1346 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#expect(Object) expect(Object)} 1347 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#forwarded(Object) forwarded(Object)} 1348 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#from(Object) from(Object)} 1349 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#hostHeader(Object) hostHeader(Object)} 1350 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#ifMatch(Object) ifMatch(Object)} 1351 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#ifModifiedSince(Object) ifModifiedSince(Object)} 1352 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#ifNoneMatch(Object) ifNoneMatch(Object)} 1353 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#ifRange(Object) ifRange(Object)} 1354 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#ifUnmodifiedSince(Object) ifUnmodifiedSince(Object)} 1355 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#maxForwards(Object) maxForwards(Object)} 1356 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#origin(Object) origin(Object)} 1357 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#pragma(Object) pragma(Object)} 1358 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#proxyAuthorization(Object) proxyAuthorization(Object)} 1359 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#range(Object) proxyAuthorization(Object)} 1360 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#referer(Object) referer(Object)} 1361 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#te(Object) te(Object)} 1362 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#userAgent(Object) userAgent(Object)} 1363 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#upgrade(Object) upgrade(Object)} 1364 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#via(Object) via(Object)} 1365 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#warning(Object) warning(Object)} 1366 * </ul> 1367 * </ul> 1368 * </ul> 1369 * 1370 * <h5 class='section'>Description:</h5> 1371 * <p> 1372 * Headers to add to every request. 1373 */ 1374 public static final String RESTCLIENT_headers = PREFIX + "headers.lo"; 1375 1376 /** 1377 * Configuration property: Ignore errors. 1378 * 1379 * <h5 class='section'>Property:</h5> 1380 * <ul class='spaced-list'> 1381 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_ignoreErrors RESTCLIENT_ignoreErrors} 1382 * <li><b>Name:</b> <js>"RestClient.ignoreErrors.b"</js> 1383 * <li><b>Data type:</b> <jk>boolean</jk> 1384 * <li><b>Default:</b> <jk>false</jk> 1385 * <li><b>Methods:</b> 1386 * <ul> 1387 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#ignoreErrors()} 1388 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#ignoreErrors(boolean)} 1389 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#ignoreErrors()} 1390 * </ul> 1391 * </ul> 1392 * 1393 * <h5 class='section'>Description:</h5> 1394 * 1395 * <p> 1396 * When enabled, HTTP error response codes (e.g. <l>>=400</l>) will not cause a {@link RestCallException} to 1397 * be thrown. 1398 * <p> 1399 * Note that this is equivalent to <c>builder.errorCodes(x -> <jk>false</jk>);</c> 1400 * 1401 * <h5 class='section'>Example:</h5> 1402 * <p class='bcode w800'> 1403 * <jc>// Create a client that doesn't throws a RestCallException when a 500 error occurs.</jc> 1404 * RestClient 1405 * .<jsm>create</jsm>() 1406 * .ignoreErrors() 1407 * .build() 1408 * .get(<js>"/error"</js>) <jc>// Throws a 500 error</jc> 1409 * .run() 1410 * .assertStatus().is(500); 1411 * </p> 1412 */ 1413 public static final String RESTCLIENT_ignoreErrors = PREFIX + "ignoreErrors.b"; 1414 1415 /** 1416 * Configuration property: Call interceptors. 1417 * 1418 * <h5 class='section'>Property:</h5> 1419 * <ul class='spaced-list'> 1420 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_interceptors RESTCLIENT_interceptors} 1421 * <li><b>Name:</b> <js>"RestClient.interceptors.lo"</js> 1422 * <li><b>Data type:</b> <c>List<Class<{@link org.apache.juneau.rest.client2.RestCallInterceptor}> | {@link org.apache.juneau.rest.client2.RestCallInterceptor}>></c> 1423 * <li><b>Default:</b> empty list. 1424 * <li><b>Methods:</b> 1425 * <ul> 1426 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#interceptors(Object...)} 1427 * </ul> 1428 * </ul> 1429 * 1430 * <h5 class='section'>Description:</h5> 1431 * <p> 1432 * Adds an interceptor that can be called to hook into specified events in the lifecycle of a single request. 1433 * 1434 * <h5 class='section'>Example:</h5> 1435 * <p class='bcode w800'> 1436 * <jc>// Customized interceptor (note you can also extend from BasicRestCallInterceptor as well.</jc> 1437 * <jk>public class</jk> MyRestCallInterceptor <jk>implements</jk> RestCallInterceptor { 1438 * 1439 * <ja>@Override</ja> 1440 * <jk>public void</jk> onInit(RestRequest <jv>req</jv>) <jk>throws</jk> Exception { 1441 * <jc>// Intercept immediately after RestRequest object is created and all headers/query/form-data has been 1442 * // set on the request from the client.</jc> 1443 * } 1444 * <ja>@Override</ja> 1445 * <jk>public void</jk> onConnect(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception { 1446 * <jc>// Intercept immediately after an HTTP response has been received.</jc> 1447 * } 1448 * 1449 * <ja>@Override</ja> 1450 * <jk>public void</jk> onClose(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception { 1451 * <jc>// Intercept when the response body is consumed.</jc> 1452 * } 1453 * } 1454 * 1455 * <jc>// Create a client with a customized interceptor.</jc> 1456 * RestClient <jv>client</jv> = RestClient 1457 * .<jsm>create</jsm>() 1458 * .interceptors(MyRestCallInterceptor.<jk>class</jk>) 1459 * .build(); 1460 * </p> 1461 */ 1462 public static final String RESTCLIENT_interceptors = PREFIX + "interceptors.lo"; 1463 1464 /** 1465 * Add to the Call interceptors property. 1466 */ 1467 public static final String RESTCLIENT_interceptors_add = PREFIX + "interceptors.so/add"; 1468 1469 /** 1470 * Configuration property: Keep HttpClient open. 1471 * 1472 * <h5 class='section'>Property:</h5> 1473 * <ul class='spaced-list'> 1474 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_keepHttpClientOpen RESTCLIENT_keepHttpClientOpen} 1475 * <li><b>Name:</b> <js>"RestClient.keepHttpClientOpen.b"</js> 1476 * <li><b>Data type:</b> <jk>boolean</jk> 1477 * <li><b>System property:</b> <c>RestClient.keepHttpClientOpen</c> 1478 * <li><b>Environment variable:</b> <c>RESTCLIENT_KEEPHTTPCLIENTOPEN</c> 1479 * <li><b>Default:</b> <jk>false</jk> 1480 * <li><b>Methods:</b> 1481 * <ul> 1482 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#keepHttpClientOpen()} 1483 * </ul> 1484 * </ul> 1485 * 1486 * <h5 class='section'>Description:</h5> 1487 * <p> 1488 * Don't close this client when the {@link RestClient#close()} method is called. 1489 * 1490 * <h5 class='section'>Example:</h5> 1491 * <p class='bcode w800'> 1492 * <jc>// Create a client with a customized client and don't close the client service.</jc> 1493 * RestClient <jv>client</jv> = RestClient 1494 * .<jsm>create</jsm>() 1495 * .httpClient(<jv>myHttpClient</jv>) 1496 * .keepHttpClientOpen() 1497 * .build(); 1498 * 1499 * <jv>client</jv>.closeQuietly(); <jc>// Customized HttpClient won't be closed.</jc> 1500 * </p> 1501 */ 1502 public static final String RESTCLIENT_keepHttpClientOpen = PREFIX + "keepHttpClientOpen.b"; 1503 1504 /** 1505 * Configuration property: Enable leak detection. 1506 * 1507 * <h5 class='section'>Property:</h5> 1508 * <ul class='spaced-list'> 1509 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_leakDetection RESTCLIENT_leakDetection} 1510 * <li><b>Name:</b> <js>"RestClient.leakDetection.b"</js> 1511 * <li><b>Data type:</b> <jk>boolean</jk> 1512 * <li><b>System property:</b> <c>RestClient.leakDetection</c> 1513 * <li><b>Environment variable:</b> <c>RESTCLIENT_LEAKDETECTION</c> 1514 * <li><b>Default:</b> <jk>false</jk> 1515 * <li><b>Methods:</b> 1516 * <ul> 1517 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#leakDetection()} 1518 * </ul> 1519 * </ul> 1520 * 1521 * <h5 class='section'>Description:</h5> 1522 * <p> 1523 * Enable client and request/response leak detection. 1524 * 1525 * <p> 1526 * Causes messages to be logged to the console if clients or request/response objects are not properly closed 1527 * when the <c>finalize</c> methods are invoked. 1528 * 1529 * <p> 1530 * Automatically enabled with {@link Context#CONTEXT_debug}. 1531 * 1532 * <h5 class='section'>Example:</h5> 1533 * <p class='bcode w800'> 1534 * <jc>// Create a client that logs a message if </jc> 1535 * RestClient <jv>client</jv> = RestClient 1536 * .<jsm>create</jsm>() 1537 * .leakDetection() 1538 * .logToConsole() <jc>// Also log the error message to System.err</jc> 1539 * .build(); 1540 * 1541 * <jv>client</jv>.closeQuietly(); <jc>// Customized HttpClient won't be closed.</jc> 1542 * </p> 1543 */ 1544 public static final String RESTCLIENT_leakDetection = PREFIX + "leakDetection.b"; 1545 1546 /** 1547 * Configuration property: Logger. 1548 * 1549 * <h5 class='section'>Property:</h5> 1550 * <ul class='spaced-list'> 1551 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_logger RESTCLIENT_logger} 1552 * <li><b>Name:</b> <js>"RestClient.logger.o"</js> 1553 * <li><b>Data type:</b> 1554 * <ul> 1555 * <li>{@link java.util.logging.Logger} 1556 * </ul> 1557 * <li><b>Default:</b> <c>Logger.<jsm>getLogger</jsm>(RestClient.<jk>class</jk>.getName())</c> 1558 * <li><b>Methods:</b> 1559 * <ul> 1560 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#logger(Logger)} 1561 * </ul> 1562 * </ul> 1563 * 1564 * <h5 class='section'>Description:</h5> 1565 * <p> 1566 * Specifies the logger to use for logging. 1567 */ 1568 public static final String RESTCLIENT_logger = PREFIX + "logger.o"; 1569 1570 /** 1571 * Configuration property: Log to console. 1572 * 1573 * <h5 class='section'>Property:</h5> 1574 * <ul class='spaced-list'> 1575 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_logToConsole RESTCLIENT_logToConsole} 1576 * <li><b>Name:</b> <js>"RestClient.logToConsole.b"</js> 1577 * <li><b>System property:</b> <c>RestClient.logToConsole</c> 1578 * <li><b>Environment variable:</b> <c>RESTCLIENT_LOGTOCONSOLE</c> 1579 * <li><b>Data type:</b> 1580 * <ul> 1581 * <li><jk>boolean</jk> 1582 * </ul> 1583 * <li><b>Default:</b> <jk>false</jk> 1584 * <li><b>Methods:</b> 1585 * <ul> 1586 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#logToConsole()} 1587 * </ul> 1588 * </ul> 1589 * 1590 * <h5 class='section'>Description:</h5> 1591 * <p> 1592 * When enabled, log messages are sent to the console in addition to the existing logger. 1593 */ 1594 public static final String RESTCLIENT_logToConsole = PREFIX + "logToConsole.b"; 1595 1596 /** 1597 * Configuration property: Log requests. 1598 * 1599 * <h5 class='section'>Property:</h5> 1600 * <ul class='spaced-list'> 1601 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_logRequests RESTCLIENT_logRequests} 1602 * <li><b>Name:</b> <js>"RestClient.logRequests.s"</js> 1603 * <li><b>System property:</b> <c>RestClient.logRequests</c> 1604 * <li><b>Environment variable:</b> <c>RESTCLIENT_LOGREQUESTS</c> 1605 * <li><b>Data type:</b> 1606 * <ul> 1607 * <li>{@link org.apache.juneau.DetailLevel} 1608 * </ul> 1609 * <li><b>Default:</b> {@link org.apache.juneau.DetailLevel#NONE} 1610 * <li><b>Methods:</b> 1611 * <ul> 1612 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#logRequests(DetailLevel,Level,BiPredicate)} 1613 * </ul> 1614 * </ul> 1615 * 1616 * <h5 class='section'>Description:</h5> 1617 * <p> 1618 * Causes requests/responses to be logged at the specified log level at the end of the request. 1619 * 1620 * <p> 1621 * <jsf>SIMPLE</jsf> detail produces a log message like the following: 1622 * <p class='bcode w800 console'> 1623 * POST http://localhost:10000/testUrl, HTTP/1.1 200 OK 1624 * </p> 1625 * 1626 * <p> 1627 * <jsf>FULL</jsf> detail produces a log message like the following: 1628 * <p class='bcode w800 console'> 1629 * === HTTP Call (outgoing) ======================================================= 1630 * === REQUEST === 1631 * POST http://localhost:10000/testUrl 1632 * ---request headers--- 1633 * Debug: true 1634 * No-Trace: true 1635 * Accept: application/json 1636 * ---request entity--- 1637 * Content-Type: application/json 1638 * ---request content--- 1639 * {"foo":"bar","baz":123} 1640 * === RESPONSE === 1641 * HTTP/1.1 200 OK 1642 * ---response headers--- 1643 * Content-Type: application/json;charset=utf-8 1644 * Content-Length: 21 1645 * Server: Jetty(8.1.0.v20120127) 1646 * ---response content--- 1647 * {"message":"OK then"} 1648 * === END ======================================================================== 1649 * </p> 1650 * 1651 * <p> 1652 * By default, the message is logged to the default logger. It can be logged to a different logger via the 1653 * {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_logger} setting or logged to the console using the 1654 * {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_logToConsole} setting. 1655 */ 1656 public static final String RESTCLIENT_logRequests = PREFIX + "logRequests.s"; 1657 1658 /** 1659 * Configuration property: Log requests log level. 1660 * 1661 * <h5 class='section'>Property:</h5> 1662 * <ul class='spaced-list'> 1663 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_logRequestsLevel RESTCLIENT_logRequestsLevel} 1664 * <li><b>Name:</b> <js>"RestClient.logRequestsLevel.s"</js> 1665 * <li><b>System property:</b> <c>RestClient.logRequestsLevel</c> 1666 * <li><b>Environment variable:</b> <c>RESTCLIENT_LOGREQUESTLEVEL</c> 1667 * <li><b>Data type:</b> 1668 * <ul> 1669 * <li>{@link java.util.logging.Level} 1670 * </ul> 1671 * <li><b>Default:</b> {@link java.util.logging.Level#INFO} 1672 * <li><b>Methods:</b> 1673 * <ul> 1674 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#logRequests(DetailLevel,Level,BiPredicate)} 1675 * </ul> 1676 * </ul> 1677 * 1678 * <h5 class='section'>Description:</h5> 1679 * <p> 1680 * Used in combination with {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_logRequests} to specify the 1681 * level to log request messages to. 1682 */ 1683 public static final String RESTCLIENT_logRequestsLevel = PREFIX + "logRequestsLevel.s"; 1684 1685 /** 1686 * Configuration property: Log requests predicate. 1687 * 1688 * <h5 class='section'>Property:</h5> 1689 * <ul class='spaced-list'> 1690 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_logRequestsPredicate RESTCLIENT_logRequestsPredicate} 1691 * <li><b>Name:</b> <js>"RestClient.logRequestsPredicate.o"</js> 1692 * <li><b>Data type:</b> 1693 * <ul> 1694 * <li>{@link java.util.function.BiPredicate}<{@link org.apache.juneau.rest.client2.RestRequest},{@link org.apache.juneau.rest.client2.RestResponse}> 1695 * </ul> 1696 * <li><b>Default:</b> <c>(req,res) -> <jk>true</jk></c> 1697 * <li><b>Methods:</b> 1698 * <ul> 1699 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#logRequests(DetailLevel,Level,BiPredicate)} 1700 * </ul> 1701 * </ul> 1702 * 1703 * <h5 class='section'>Description:</h5> 1704 * <p> 1705 * Used in combination with {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_logRequests} to specify the 1706 * level to log request messages to. 1707 */ 1708 public static final String RESTCLIENT_logRequestsPredicate = PREFIX + "logRequestsPredicate.o"; 1709 1710 /** 1711 * Configuration property: Parsers. 1712 * 1713 * <h5 class='section'>Property:</h5> 1714 * <ul class='spaced-list'> 1715 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_parsers RESTCLIENT_parsers} 1716 * <li><b>Name:</b> <js>"RestClient.parsers.lo"</js> 1717 * <li><b>Data type:</b> 1718 * <ul> 1719 * <li><c>Class<? <jk>extends</jk> {@link org.apache.juneau.parser.Parser}></c> 1720 * <li>{@link org.apache.juneau.parser.Parser} 1721 * </ul> 1722 * <li><b>Default:</b> No parsers. 1723 * <li><b>Methods:</b> 1724 * <ul> 1725 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#parser(Class)} 1726 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#parser(Parser)} 1727 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#parsers(Class...)} 1728 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#parsers(Parser...)} 1729 * </ul> 1730 * </ul> 1731 * 1732 * <h5 class='section'>Description:</h5> 1733 * <p> 1734 * Associates the specified {@link Parser Parsers} with the HTTP client. 1735 * 1736 * <p> 1737 * The parsers are used to parse the HTTP response body into a POJO. 1738 * 1739 * <p> 1740 * The parser that best matches the <c>Accept</c> header will be used to parse the response body. 1741 * <br>If no <c>Accept</c> header is specified, the first parser in the list will be used. 1742 * 1743 * <h5 class='section'>Example:</h5> 1744 * <p class='bcode w800'> 1745 * <jc>// Create a client that uses JSON and XML transport for response bodies.</jc> 1746 * RestClient <jv>client</jv> = RestClient 1747 * .<jsm>create</jsm>() 1748 * .parser(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>) 1749 * .strict() <jc>// Enable strict mode on parsers.</jc> 1750 * .build(); 1751 * </p> 1752 */ 1753 public static final String RESTCLIENT_parsers = PREFIX + "parsers.lo"; 1754 1755 /** 1756 * Configuration property: Part parser. 1757 * 1758 * <h5 class='section'>Property:</h5> 1759 * <ul class='spaced-list'> 1760 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_partParser RESTCLIENT_partParser} 1761 * <li><b>Name:</b> <js>"RestClient.partParser.o"</js> 1762 * <li><b>Data type:</b> 1763 * <ul> 1764 * <li><c>Class<? <jk>extends</jk> {@link org.apache.juneau.httppart.HttpPartParser}></c> 1765 * <li>{@link org.apache.juneau.httppart.HttpPartParser} 1766 * </ul> 1767 * <li><b>Default:</b> {@link org.apache.juneau.oapi.OpenApiParser}; 1768 * <li><b>Methods:</b> 1769 * <ul> 1770 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#partParser(Class)} 1771 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#partParser(HttpPartParser)} 1772 * </ul> 1773 * </ul> 1774 * 1775 * <h5 class='section'>Description:</h5> 1776 * <p> 1777 * The parser to use for parsing POJOs from form data, query parameters, headers, and path variables. 1778 * 1779 * <p> 1780 * The default part parser is {@link OpenApiParser} which allows for schema-driven marshalling. 1781 * 1782 * <h5 class='section'>Example:</h5> 1783 * <p class='bcode w800'> 1784 * <jc>// Create a client that uses UON format by default for incoming HTTP parts.</jc> 1785 * RestClient <jv>client</jv> = RestClient 1786 * .<jsm>create</jsm>() 1787 * .partParser(UonParser.<jk>class</jk>) 1788 * .build(); 1789 * </p> 1790 */ 1791 public static final String RESTCLIENT_partParser = PREFIX + "partParser.o"; 1792 1793 /** 1794 * Configuration property: Part serializer. 1795 * 1796 * <h5 class='section'>Property:</h5> 1797 * <ul class='spaced-list'> 1798 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_partSerializer RESTCLIENT_partSerializer} 1799 * <li><b>Name:</b> <js>"RestClient.partSerializer.o"</js> 1800 * <li><b>Data type:</b> 1801 * <ul> 1802 * <li><c>Class<? <jk>extends</jk> {@link org.apache.juneau.httppart.HttpPartSerializer}></c> 1803 * <li>{@link org.apache.juneau.httppart.HttpPartSerializer} 1804 * </ul> 1805 * <li><b>Default:</b> {@link org.apache.juneau.oapi.OpenApiSerializer}; 1806 * <li><b>Methods:</b> 1807 * <ul> 1808 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#partSerializer(Class)} 1809 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#partSerializer(HttpPartSerializer)} 1810 * </ul> 1811 * </ul> 1812 * 1813 * <h5 class='section'>Description:</h5> 1814 * <p> 1815 * The serializer to use for serializing POJOs in form data, query parameters, headers, and path variables. 1816 * 1817 * <p> 1818 * The default part serializer is {@link OpenApiSerializer} which allows for schema-driven marshalling. 1819 * 1820 * <h5 class='section'>Example:</h5> 1821 * <p class='bcode w800'> 1822 * <jc>// Create a client that uses UON format by default for outgoing HTTP parts.</jc> 1823 * RestClient <jv>client</jv> = RestClient 1824 * .<jsm>create</jsm>() 1825 * .partSerializer(UonSerializer.<jk>class</jk>) 1826 * .build(); 1827 * </p> 1828 */ 1829 public static final String RESTCLIENT_partSerializer = PREFIX + "partSerializer.o"; 1830 1831 /** 1832 * Configuration property: Request query parameters. 1833 * 1834 * <h5 class='section'>Property:</h5> 1835 * <ul class='spaced-list'> 1836 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_query RESTCLIENT_query} 1837 * <li><b>Name:</b> <js>"RestClient.query.lo"</js> 1838 * <li><b>Data type:</b> <c>List<{@link org.apache.http.NameValuePair}></c> 1839 * <li><b>Default:</b> empty map 1840 * <li><b>Methods:</b> 1841 * <ul> 1842 * <li class='jc'>{@link org.apache.juneau.rest.client2.RestClientBuilder} 1843 * <ul> 1844 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#queries(Object...) queries(Object...)} 1845 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#query(String,Object) query(String,Object)} 1846 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#query(String,Object,HttpPartSchema,HttpPartSerializer) query(String,Object,HttpPartSerializer,HttpPartSchema)} 1847 * </ul> 1848 * <li class='jc'>{@link org.apache.juneau.rest.client2.RestRequest} 1849 * <ul> 1850 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#query(String,Object) query(String,Object)} 1851 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#query(AddFlag,String,Object) query(EnumSet<AddFlag>,String,Object)} 1852 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#queries(Object...) queries(Object...)} 1853 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#queries(AddFlag,Object...) queries(EnumSet<AddFlag>,Object...)} 1854 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#queryPairs(Object...) queryPairs(Object...)} 1855 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#queryCustom(Object) queryCustom(Object)} 1856 * </ul> 1857 * </ul> 1858 * </ul> 1859 * 1860 * <h5 class='section'>Description:</h5> 1861 * <p> 1862 * Query parameters to add to every request. 1863 */ 1864 public static final String RESTCLIENT_query = PREFIX + "query.lo"; 1865 1866 /** 1867 * Configuration property: Root URI. 1868 * 1869 * <h5 class='section'>Property:</h5> 1870 * <ul class='spaced-list'> 1871 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_rootUri RESTCLIENT_rootUri} 1872 * <li><b>Name:</b> <js>"RestClient.rootUri.s"</js> 1873 * <li><b>Data type:</b> <c>String</c> 1874 * <li><b>System property:</b> <c>RestClient.rootUri</c> 1875 * <li><b>Environment variable:</b> <c>RESTCLIENT_ROOTURI</c> 1876 * <li><b>Default:</b> <jk>false</jk> 1877 * <li><b>Methods:</b> 1878 * <ul> 1879 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#rootUri(Object)} 1880 * </ul> 1881 * </ul> 1882 * 1883 * <h5 class='section'>Description:</h5> 1884 * <p> 1885 * When set, relative URI strings passed in through the various rest call methods (e.g. {@link RestClient#get(Object)} 1886 * will be prefixed with the specified root. 1887 * <br>This root URI is ignored on those methods if you pass in a {@link URL}, {@link URI}, or an absolute URI string. 1888 * 1889 * <h5 class='section'>Example:</h5> 1890 * <p class='bcode w800'> 1891 * <jc>// Create a client that uses UON format by default for HTTP parts.</jc> 1892 * RestClient <jv>client</jv> = RestClient 1893 * .<jsm>create</jsm>() 1894 * .rootUri(<js>"http://localhost:10000/foo"</js>) 1895 * .build(); 1896 * 1897 * Bar <jv>bar</jv> = <jv>client</jv> 1898 * .get(<js>"/bar"</js>) <jc>// Relative to http://localhost:10000/foo</jc> 1899 * .run() 1900 * .getBody().as(Bar.<jk>class</jk>); 1901 * </p> 1902 */ 1903 public static final String RESTCLIENT_rootUri = PREFIX + "rootUri.s"; 1904 1905 /** 1906 * Configuration property: Serializers. 1907 * 1908 * <h5 class='section'>Property:</h5> 1909 * <ul class='spaced-list'> 1910 * <li><b>ID:</b> {@link org.apache.juneau.rest.client2.RestClient#RESTCLIENT_serializers RESTCLIENT_serializers} 1911 * <li><b>Name:</b> <js>"RestClient.serializers.lo"</js> 1912 * <li><b>Data type:</b> 1913 * <ul> 1914 * <li><c>Class<? <jk>extends</jk> {@link org.apache.juneau.serializer.Serializer}></c> 1915 * <li>{@link org.apache.juneau.serializer.Serializer} 1916 * </ul> 1917 * <li><b>Default:</b> No serializers. 1918 * <li><b>Methods:</b> 1919 * <ul> 1920 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#serializer(Class)} 1921 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#serializer(Serializer)} 1922 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#serializers(Class...)} 1923 * <li class='jm'>{@link org.apache.juneau.rest.client2.RestClientBuilder#serializers(Serializer...)} 1924 * </ul> 1925 * </ul> 1926 * 1927 * <h5 class='section'>Description:</h5> 1928 * <p> 1929 * Associates the specified {@link Serializer Serializers} with the HTTP client. 1930 * 1931 * <p> 1932 * The serializer is used to serialize POJOs into the HTTP request body. 1933 * 1934 * <p> 1935 * The serializer that best matches the <c>Content-Type</c> header will be used to serialize the request body. 1936 * <br>If no <c>Content-Type</c> header is specified, the first serializer in the list will be used. 1937 * 1938 * <h5 class='section'>Example:</h5> 1939 * <p class='bcode w800'> 1940 * <jc>// Create a client that uses JSON and XML transport for request bodies.</jc> 1941 * RestClient <jv>client</jv> = RestClient 1942 * .<jsm>create</jsm>() 1943 * .serializers(JsonSerializer.<jk>class</jk>,XmlSerializer.<jk>class</jk>) 1944 * .sortCollections() <jc>// Sort any collections being serialized.</jc> 1945 * .build(); 1946 * </p> 1947 */ 1948 public static final String RESTCLIENT_serializers = PREFIX + "serializers.lo"; 1949 1950 static final String RESTCLIENT_httpClient = PREFIX + "httpClient.o"; 1951 static final String RESTCLIENT_httpClientBuilder= PREFIX + "httpClientBuilder.o"; 1952 1953 private final HeaderSupplier headers; 1954 private final NameValuePairSupplier query, formData; 1955 final CloseableHttpClient httpClient; 1956 private final boolean keepHttpClientOpen, leakDetection; 1957 private final UrlEncodingSerializer urlEncodingSerializer; // Used for form posts only. 1958 private final HttpPartSerializer partSerializer; 1959 private final HttpPartParser partParser; 1960 private final RestCallHandler callHandler; 1961 private final String rootUri; 1962 private volatile boolean isClosed = false; 1963 private final StackTraceElement[] creationStack; 1964 private final Logger logger; 1965 final DetailLevel logRequests; 1966 final BiPredicate<RestRequest,RestResponse> logRequestsPredicate; 1967 final Level logRequestsLevel; 1968 final boolean ignoreErrors; 1969 private final boolean logToConsole; 1970 private final PrintStream console; 1971 private StackTraceElement[] closedStack; 1972 private static final ConcurrentHashMap<Class<?>,Context> requestContexts = new ConcurrentHashMap<>(); 1973 1974 // These are read directly by RestCall. 1975 final SerializerGroup serializers; 1976 final ParserGroup parsers; 1977 Predicate<Integer> errorCodes; 1978 1979 final RestCallInterceptor[] interceptors; 1980 1981 // This is lazy-created. 1982 private volatile ExecutorService executorService; 1983 private final boolean executorServiceShutdownOnClose; 1984 1985 /** 1986 * Instantiates a new clean-slate {@link RestClientBuilder} object. 1987 * 1988 * @return A new {@link RestClientBuilder} object. 1989 */ 1990 public static RestClientBuilder create() { 1991 return new RestClientBuilder(PropertyStore.DEFAULT); 1992 } 1993 1994 @Override /* Context */ 1995 public RestClientBuilder builder() { 1996 return new RestClientBuilder(getPropertyStore()); 1997 } 1998 1999 private static final 2000 Predicate<Integer> ERROR_CODES_DEFAULT = x -> x<=0 || x>=400; 2001 2002 private static final 2003 BiPredicate<RestRequest,RestResponse> LOG_REQUESTS_PREDICATE_DEFAULT = (req,res) -> true; 2004 2005 /** 2006 * Constructor. 2007 * 2008 * @param ps The property store containing the unmodifiable configuration for this client. 2009 */ 2010 @SuppressWarnings("unchecked") 2011 protected RestClient(PropertyStore ps) { 2012 super(ps); 2013 this.httpClient = getInstanceProperty(RESTCLIENT_httpClient, CloseableHttpClient.class, null); 2014 this.keepHttpClientOpen = getBooleanProperty(RESTCLIENT_keepHttpClientOpen, false); 2015 this.errorCodes = getInstanceProperty(RESTCLIENT_errorCodes, Predicate.class, ERROR_CODES_DEFAULT); 2016 this.executorServiceShutdownOnClose = getBooleanProperty(RESTCLIENT_executorServiceShutdownOnClose, false); 2017 this.rootUri = StringUtils.nullIfEmpty(getStringProperty(RESTCLIENT_rootUri, "").replaceAll("\\/$", "")); 2018 this.leakDetection = getBooleanProperty(RESTCLIENT_leakDetection, isDebug()); 2019 this.ignoreErrors = getBooleanProperty(RESTCLIENT_ignoreErrors, false); 2020 this.logger = getInstanceProperty(RESTCLIENT_logger, Logger.class, Logger.getLogger(RestClient.class.getName())); 2021 this.logRequests = getInstanceProperty(RESTCLIENT_logRequests, DetailLevel.class, isDebug() ? DetailLevel.FULL : DetailLevel.NONE); 2022 this.logRequestsLevel = getInstanceProperty(RESTCLIENT_logRequestsLevel, Level.class, isDebug() ? Level.WARNING : Level.OFF); 2023 this.logToConsole = getBooleanProperty(RESTCLIENT_logToConsole, isDebug()); 2024 this.console = getInstanceProperty(RESTCLIENT_console, PrintStream.class, System.err); 2025 this.logRequestsPredicate = getInstanceProperty(RESTCLIENT_logRequestsPredicate, BiPredicate.class, LOG_REQUESTS_PREDICATE_DEFAULT); 2026 2027 SerializerGroupBuilder sgb = SerializerGroup.create(); 2028 for (Object o : getArrayProperty(RESTCLIENT_serializers, Object.class)) { 2029 if (o instanceof Serializer) { 2030 sgb.append((Serializer)o); // Don't apply PropertyStore. 2031 } else if (o instanceof Class) { 2032 Class<?> c = (Class<?>)o; 2033 if (! Serializer.class.isAssignableFrom(c)) 2034 throw new ConfigException("RESTCLIENT_serializers property had invalid class of type ''{0}''", c.getName()); 2035 sgb.append(ContextCache.INSTANCE.create((Class<? extends Serializer>)o, ps)); 2036 } else { 2037 throw new ConfigException("RESTCLIENT_serializers property had invalid object of type ''{0}''", o.getClass().getName()); 2038 } 2039 } 2040 this.serializers = sgb.build(); 2041 2042 ParserGroupBuilder pgb = ParserGroup.create(); 2043 for (Object o : getArrayProperty(RESTCLIENT_parsers, Object.class)) { 2044 if (o instanceof Parser) { 2045 pgb.append((Parser)o); // Don't apply PropertyStore. 2046 } else if (o instanceof Class) { 2047 Class<?> c = (Class<?>)o; 2048 if (! Parser.class.isAssignableFrom(c)) 2049 throw new ConfigException("RESTCLIENT_parsers property had invalid class of type ''{0}''", c.getName()); 2050 pgb.append(ContextCache.INSTANCE.create((Class<? extends Parser>)o, ps)); 2051 } else { 2052 throw new ConfigException("RESTCLIENT_parsers property had invalid object of type ''{0}''", o.getClass().getName()); 2053 } 2054 } 2055 this.parsers = pgb.build(); 2056 2057 this.urlEncodingSerializer = new SerializerBuilder(ps).build(UrlEncodingSerializer.class); 2058 this.partSerializer = getInstanceProperty(RESTCLIENT_partSerializer, HttpPartSerializer.class, OpenApiSerializer.class, ResourceResolver.FUZZY, ps); 2059 this.partParser = getInstanceProperty(RESTCLIENT_partParser, HttpPartParser.class, OpenApiParser.class, ResourceResolver.FUZZY, ps); 2060 this.executorService = getInstanceProperty(RESTCLIENT_executorService, ExecutorService.class, null); 2061 2062 HttpPartSerializerSession partSerializerSession = partSerializer.createPartSession(null); 2063 2064 this.headers = HeaderSupplier.create(); 2065 for (Object o : getListProperty(RESTCLIENT_headers, Object.class)) { 2066 o = buildBuilders(o, partSerializerSession); 2067 if (o instanceof HeaderSupplier) 2068 headers.add((HeaderSupplier)o); 2069 else 2070 headers.add(BasicHeader.cast(o)); 2071 } 2072 2073 this.query = NameValuePairSupplier.create(); 2074 for (Object o : getListProperty(RESTCLIENT_query, Object.class)) { 2075 o = buildBuilders(o, partSerializerSession); 2076 if (o instanceof NameValuePairSupplier) 2077 query.add((NameValuePairSupplier)o); 2078 else 2079 query.add(BasicNameValuePair.cast(o)); 2080 } 2081 2082 this.formData = NameValuePairSupplier.create(); 2083 for (Object o : getListProperty(RESTCLIENT_formData, Object.class)) { 2084 o = buildBuilders(o, partSerializerSession); 2085 if (o instanceof NameValuePairSupplier) 2086 formData.add((NameValuePairSupplier)o); 2087 else 2088 formData.add(BasicNameValuePair.cast(o)); 2089 } 2090 2091 this.callHandler = getInstanceProperty(RESTCLIENT_callHandler, RestCallHandler.class, BasicRestCallHandler.class, ResourceResolver.FUZZY, ps, this); 2092 2093 this.interceptors = getInstanceArrayProperty(RESTCLIENT_interceptors, RestCallInterceptor.class, new RestCallInterceptor[0]); 2094 2095 creationStack = isDebug() ? Thread.currentThread().getStackTrace() : null; 2096 } 2097 2098 private static Object buildBuilders(Object o, HttpPartSerializerSession ss) { 2099 if (o instanceof SerializedHeader) 2100 return ((SerializedHeader)o).serializer(ss, false); 2101 if (o instanceof SerializedNameValuePair) 2102 return ((SerializedNameValuePair)o).serializer(ss, false); 2103 return o; 2104 } 2105 2106 /** 2107 * Calls {@link CloseableHttpClient#close()} on the underlying {@link CloseableHttpClient}. 2108 * 2109 * <p> 2110 * It's good practice to call this method after the client is no longer used. 2111 * 2112 * @throws IOException Thrown by underlying stream. 2113 */ 2114 @Override 2115 public void close() throws IOException { 2116 isClosed = true; 2117 if (! keepHttpClientOpen) 2118 httpClient.close(); 2119 if (executorService != null && executorServiceShutdownOnClose) 2120 executorService.shutdown(); 2121 if (creationStack != null) 2122 closedStack = Thread.currentThread().getStackTrace(); 2123 } 2124 2125 /** 2126 * Same as {@link #close()}, but ignores any exceptions. 2127 */ 2128 public void closeQuietly() { 2129 isClosed = true; 2130 try { 2131 if (! keepHttpClientOpen) 2132 httpClient.close(); 2133 if (executorService != null && executorServiceShutdownOnClose) 2134 executorService.shutdown(); 2135 } catch (Throwable t) {} 2136 if (creationStack != null) 2137 closedStack = Thread.currentThread().getStackTrace(); 2138 } 2139 2140 /** 2141 * Entrypoint for executing all requests and returning a response. 2142 * 2143 * <p> 2144 * Subclasses can override this method to provide specialized handling. 2145 * 2146 * <p> 2147 * The behavior of this method can also be modified by specifying a different {@link RestCallHandler}. 2148 * 2149 * <ul class='seealso'> 2150 * <li class='jf'>{@link RestClient#RESTCLIENT_callHandler} 2151 * <li class='jm'>{@link RestClientBuilder#callHandler(Class)} 2152 * <li class='jm'>{@link RestClientBuilder#callHandler(RestCallHandler)} 2153 * </ul> 2154 * 2155 * @param target The target host for the request. 2156 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default 2157 * target or by inspecting the request. 2158 * @param request The request to execute. 2159 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 2160 * @return 2161 * The response to the request. 2162 * <br>This is always a final response, never an intermediate response with an 1xx status code. 2163 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 2164 * implementation and configuration of this client. 2165 * @throws IOException In case of a problem or the connection was aborted. 2166 * @throws ClientProtocolException In case of an http protocol error. 2167 */ 2168 @Override /* RestCallHandler */ 2169 public HttpResponse run(HttpHost target, HttpRequest request, HttpContext context) throws ClientProtocolException, IOException { 2170 return callHandler.run(target, request, context); 2171 } 2172 2173 /** 2174 * Perform a <c>GET</c> request against the specified URI. 2175 * 2176 * @param uri 2177 * The URI of the remote REST resource. 2178 * <br>Can be any of the following types: 2179 * <ul> 2180 * <li>{@link URIBuilder} 2181 * <li>{@link URI} 2182 * <li>{@link URL} 2183 * <li>{@link String} 2184 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2185 * </ul> 2186 * @return 2187 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2188 * as a parsed object. 2189 * @throws RestCallException If any authentication errors occurred. 2190 */ 2191 public RestRequest get(Object uri) throws RestCallException { 2192 return request("GET", uri, false); 2193 } 2194 2195 /** 2196 * Perform a <c>GET</c> request against the root URI. 2197 * 2198 * @return 2199 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2200 * as a parsed object. 2201 * @throws RestCallException If any authentication errors occurred. 2202 */ 2203 public RestRequest get() throws RestCallException { 2204 return request("GET", null, false); 2205 } 2206 2207 /** 2208 * Perform a <c>PUT</c> request against the specified URI. 2209 * 2210 * @param uri 2211 * The URI of the remote REST resource. 2212 * <br>Can be any of the following types: 2213 * <ul> 2214 * <li>{@link URIBuilder} 2215 * <li>{@link URI} 2216 * <li>{@link URL} 2217 * <li>{@link String} 2218 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2219 * </ul> 2220 * @param body 2221 * The object to serialize and transmit to the URI as the body of the request. 2222 * Can be of the following types: 2223 * <ul class='spaced-list'> 2224 * <li> 2225 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 2226 * <li> 2227 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 2228 * <li> 2229 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 2230 * {@link RestClient}. 2231 * <li> 2232 * {@link HttpEntity} / {@link HttpResource} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 2233 * <li> 2234 * {@link NameValuePairSupplier} - Converted to a URL-encoded FORM post. 2235 * <li> 2236 * {@link Supplier} - A supplier of anything on this list. 2237 * </ul> 2238 * @return 2239 * A {@link RestRequest} object that can be further tailored before executing the request 2240 * and getting the response as a parsed object. 2241 * @throws RestCallException If any authentication errors occurred. 2242 */ 2243 public RestRequest put(Object uri, Object body) throws RestCallException { 2244 return request("PUT", uri, true).body(body); 2245 } 2246 2247 /** 2248 * Perform a <c>PUT</c> request against the specified URI using a plain text body bypassing the serializer. 2249 * 2250 * @param uri 2251 * The URI of the remote REST resource. 2252 * <br>Can be any of the following types: 2253 * <ul> 2254 * <li>{@link URIBuilder} 2255 * <li>{@link URI} 2256 * <li>{@link URL} 2257 * <li>{@link String} 2258 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2259 * </ul> 2260 * @param body 2261 * The object to serialize and transmit to the URI as the body of the request bypassing the serializer. 2262 * @param contentType The content type of the request. 2263 * @return 2264 * A {@link RestRequest} object that can be further tailored before executing the request 2265 * and getting the response as a parsed object. 2266 * @throws RestCallException If any authentication errors occurred. 2267 */ 2268 public RestRequest put(Object uri, String body, String contentType) throws RestCallException { 2269 return request("PUT", uri, true).bodyString(body).contentType(contentType); 2270 } 2271 2272 /** 2273 * Same as {@link #put(Object, Object)} but don't specify the input yet. 2274 * 2275 * <p> 2276 * You must call either {@link RestRequest#body(Object)} or {@link RestRequest#formData(String, Object)} 2277 * to set the contents on the result object. 2278 * 2279 * @param uri 2280 * The URI of the remote REST resource. 2281 * <br>Can be any of the following types: 2282 * <ul> 2283 * <li>{@link URIBuilder} 2284 * <li>{@link URI} 2285 * <li>{@link URL} 2286 * <li>{@link String} 2287 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2288 * </ul> 2289 * @return 2290 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2291 * as a parsed object. 2292 * @throws RestCallException REST call failed. 2293 */ 2294 public RestRequest put(Object uri) throws RestCallException { 2295 return request("PUT", uri, true); 2296 } 2297 2298 /** 2299 * Perform a <c>POST</c> request against the specified URI. 2300 * 2301 * <ul class='notes'> 2302 * <li>Use {@link #formPost(Object, Object)} for <c>application/x-www-form-urlencoded</c> form posts. 2303 * </ul> 2304 * 2305 * @param uri 2306 * The URI of the remote REST resource. 2307 * <br>Can be any of the following types: 2308 * <ul> 2309 * <li>{@link URIBuilder} 2310 * <li>{@link URI} 2311 * <li>{@link URL} 2312 * <li>{@link String} 2313 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2314 * </ul> 2315 * @param body 2316 * The object to serialize and transmit to the URI as the body of the request. 2317 * Can be of the following types: 2318 * <ul class='spaced-list'> 2319 * <li> 2320 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 2321 * <li> 2322 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 2323 * <li> 2324 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 2325 * {@link RestClient}. 2326 * <li> 2327 * {@link HttpEntity} / {@link HttpResource} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 2328 * <li> 2329 * {@link NameValuePairSupplier} - Converted to a URL-encoded FORM post. 2330 * <li> 2331 * {@link Supplier} - A supplier of anything on this list. 2332 * </ul> 2333 * @return 2334 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2335 * as a parsed object. 2336 * @throws RestCallException If any authentication errors occurred. 2337 */ 2338 public RestRequest post(Object uri, Object body) throws RestCallException { 2339 return request("POST", uri, true).body(body); 2340 } 2341 2342 /** 2343 * Perform a <c>POST</c> request against the specified URI as a plain text body bypassing the serializer. 2344 * 2345 * @param uri 2346 * The URI of the remote REST resource. 2347 * <br>Can be any of the following types: 2348 * <ul> 2349 * <li>{@link URIBuilder} 2350 * <li>{@link URI} 2351 * <li>{@link URL} 2352 * <li>{@link String} 2353 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2354 * </ul> 2355 * @param body 2356 * The object to serialize and transmit to the URI as the body of the request bypassing the serializer. 2357 * @param contentType 2358 * The content type of the request. 2359 * @return 2360 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2361 * as a parsed object. 2362 * @throws RestCallException If any authentication errors occurred. 2363 */ 2364 public RestRequest post(Object uri, String body, String contentType) throws RestCallException { 2365 return request("POST", uri, true).bodyString(body).contentType(contentType); 2366 } 2367 2368 /** 2369 * Same as {@link #post(Object, Object)} but don't specify the input yet. 2370 * 2371 * <p> 2372 * You must call either {@link RestRequest#body(Object)} or {@link RestRequest#formData(String, Object)} to set the 2373 * contents on the result object. 2374 * 2375 * <ul class='notes'> 2376 * <li>Use {@link #formPost(Object, Object)} for <c>application/x-www-form-urlencoded</c> form posts. 2377 * </ul> 2378 * 2379 * @param uri 2380 * The URI of the remote REST resource. 2381 * <br>Can be any of the following types: 2382 * <ul> 2383 * <li>{@link URIBuilder} 2384 * <li>{@link URI} 2385 * <li>{@link URL} 2386 * <li>{@link String} 2387 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2388 * </ul> 2389 * @return 2390 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2391 * as a parsed object. 2392 * @throws RestCallException REST call failed. 2393 */ 2394 public RestRequest post(Object uri) throws RestCallException { 2395 return request("POST", uri, true); 2396 } 2397 2398 /** 2399 * Perform a <c>DELETE</c> request against the specified URI. 2400 * 2401 * @param uri 2402 * The URI of the remote REST resource. 2403 * <br>Can be any of the following types: 2404 * <ul> 2405 * <li>{@link URIBuilder} 2406 * <li>{@link URI} 2407 * <li>{@link URL} 2408 * <li>{@link String} 2409 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2410 * </ul> 2411 * @return 2412 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2413 * as a parsed object. 2414 * @throws RestCallException If any authentication errors occurred. 2415 */ 2416 public RestRequest delete(Object uri) throws RestCallException { 2417 return request("DELETE", uri, false); 2418 } 2419 2420 /** 2421 * Perform an <c>OPTIONS</c> request against the specified URI. 2422 * 2423 * @param uri 2424 * The URI of the remote REST resource. 2425 * <br>Can be any of the following types: 2426 * <ul> 2427 * <li>{@link URIBuilder} 2428 * <li>{@link URI} 2429 * <li>{@link URL} 2430 * <li>{@link String} 2431 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2432 * </ul> 2433 * @return 2434 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2435 * as a parsed object. 2436 * @throws RestCallException If any authentication errors occurred. 2437 */ 2438 public RestRequest options(Object uri) throws RestCallException { 2439 return request("OPTIONS", uri, true); 2440 } 2441 2442 /** 2443 * Perform a <c>HEAD</c> request against the specified URI. 2444 * 2445 * @param uri 2446 * The URI of the remote REST resource. 2447 * <br>Can be any of the following types: 2448 * <ul> 2449 * <li>{@link URIBuilder} 2450 * <li>{@link URI} 2451 * <li>{@link URL} 2452 * <li>{@link String} 2453 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2454 * </ul> 2455 * @return 2456 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2457 * as a parsed object. 2458 * @throws RestCallException If any authentication errors occurred. 2459 */ 2460 public RestRequest head(Object uri) throws RestCallException { 2461 return request("HEAD", uri, false); 2462 } 2463 2464 /** 2465 * Perform a <c>POST</c> request with a content type of <c>application/x-www-form-urlencoded</c> 2466 * against the specified URI. 2467 * 2468 * @param uri 2469 * The URI of the remote REST resource. 2470 * <br>Can be any of the following types: 2471 * <ul> 2472 * <li>{@link URIBuilder} 2473 * <li>{@link URI} 2474 * <li>{@link URL} 2475 * <li>{@link String} 2476 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2477 * </ul> 2478 * @param body 2479 * The object to serialize and transmit to the URI as the body of the request. 2480 * <ul class='spaced-list'> 2481 * <li>{@link NameValuePair} - URL-encoded as a single name-value pair. 2482 * <li>{@link NameValuePair} array - URL-encoded as name value pairs. 2483 * <li>{@link NameValuePairSupplier} - URL-encoded as name value pairs. 2484 * <li>{@link Reader}/{@link InputStream}- Streamed directly and <l>Content-Type</l> set to <js>"application/x-www-form-urlencoded"</js> 2485 * <li>{@link HttpResource}/{@link BasicHttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 2486 * <li>{@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 2487 * <li>{@link Object} - Converted to a {@link SerializedHttpEntity} using {@link UrlEncodingSerializer} to serialize. 2488 * <li>{@link Supplier} - A supplier of anything on this list. 2489 * </ul> 2490 * @return 2491 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2492 * as a parsed object. 2493 * @throws RestCallException If any authentication errors occurred. 2494 */ 2495 public RestRequest formPost(Object uri, Object body) throws RestCallException { 2496 RestRequest req = request("POST", uri, true); 2497 try { 2498 if (body instanceof Supplier) 2499 body = ((Supplier<?>)body).get(); 2500 if (body instanceof NameValuePair) 2501 return req.body(new UrlEncodedFormEntity(AList.of((NameValuePair)body))); 2502 if (body instanceof NameValuePair[]) 2503 return req.body(new UrlEncodedFormEntity(Arrays.asList((NameValuePair[])body))); 2504 if (body instanceof NameValuePairSupplier) 2505 return req.body(new UrlEncodedFormEntity((NameValuePairSupplier)body)); 2506 if (body instanceof HttpResource) { 2507 for (Header h : ((HttpResource)body).getHeaders()) 2508 req.header(h); 2509 } 2510 if (body instanceof HttpEntity) { 2511 HttpEntity e = (HttpEntity)body; 2512 if (e.getContentType() == null) 2513 req.contentType("application/x-www-form-urlencoded"); 2514 return req.body(e); 2515 } 2516 if (body instanceof Reader || body instanceof InputStream) 2517 return req.contentType("application/x-www-form-urlencoded").body(body); 2518 return req.body(SerializedHttpEntity.of(body, urlEncodingSerializer)); 2519 } catch (IOException e) { 2520 throw new RestCallException(null, e, "Could not read form post body."); 2521 } 2522 } 2523 2524 /** 2525 * Same as {@link #formPost(Object, Object)} but doesn't specify the input yet. 2526 * 2527 * @param uri 2528 * The URI of the remote REST resource. 2529 * <br>Can be any of the following types: 2530 * <ul> 2531 * <li>{@link URIBuilder} 2532 * <li>{@link URI} 2533 * <li>{@link URL} 2534 * <li>{@link String} 2535 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2536 * </ul> 2537 * @return 2538 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2539 * as a parsed object. 2540 * @throws RestCallException If any authentication errors occurred. 2541 */ 2542 public RestRequest formPost(Object uri) throws RestCallException { 2543 return request("POST", uri, true); 2544 } 2545 2546 /** 2547 * Perform a <c>POST</c> request with a content type of <c>application/x-www-form-urlencoded</c> 2548 * against the specified URI. 2549 * 2550 * @param uri 2551 * The URI of the remote REST resource. 2552 * <br>Can be any of the following types: 2553 * <ul> 2554 * <li>{@link URIBuilder} 2555 * <li>{@link URI} 2556 * <li>{@link URL} 2557 * <li>{@link String} 2558 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2559 * </ul> 2560 * @param parameters 2561 * The parameters of the form post. 2562 * <br>The parameters represent name/value pairs and must be an even number of arguments. 2563 * <br>Parameters are converted to {@link BasicNameValuePair} objects. 2564 * @return 2565 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2566 * as a parsed object. 2567 * @throws RestCallException If any authentication errors occurred. 2568 */ 2569 public RestRequest formPostPairs(Object uri, Object...parameters) throws RestCallException { 2570 return formPost(uri, NameValuePairSupplier.ofPairs(parameters)); 2571 } 2572 2573 /** 2574 * Perform a <c>PATCH</c> request against the specified URI. 2575 * 2576 * @param uri 2577 * The URI of the remote REST resource. 2578 * <br>Can be any of the following types: 2579 * <ul> 2580 * <li>{@link URIBuilder} 2581 * <li>{@link URI} 2582 * <li>{@link URL} 2583 * <li>{@link String} 2584 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2585 * </ul> 2586 * @param body 2587 * The object to serialize and transmit to the URI as the body of the request. 2588 * Can be of the following types: 2589 * <ul class='spaced-list'> 2590 * <li> 2591 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 2592 * <li> 2593 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 2594 * <li> 2595 * {@link HttpResource}/{@link BasicHttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 2596 * <li> 2597 * {@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 2598 * <li> 2599 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 2600 * {@link RestClient}. 2601 * <li> 2602 * {@link NameValuePairSupplier} - Converted to a URL-encoded FORM post. 2603 * <li> 2604 * {@link Supplier} - A supplier of anything on this list. 2605 * </ul> 2606 * @return 2607 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2608 * as a parsed object. 2609 * @throws RestCallException If any authentication errors occurred. 2610 */ 2611 public RestRequest patch(Object uri, Object body) throws RestCallException { 2612 return request("PATCH", uri, true).body(body); 2613 } 2614 2615 /** 2616 * Perform a <c>PATCH</c> request against the specified URI as a plain text body bypassing the serializer. 2617 * 2618 * @param uri 2619 * The URI of the remote REST resource. 2620 * <br>Can be any of the following types: 2621 * <ul> 2622 * <li>{@link URIBuilder} 2623 * <li>{@link URI} 2624 * <li>{@link URL} 2625 * <li>{@link String} 2626 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2627 * </ul> 2628 * @param body 2629 * The object to serialize and transmit to the URI as the body of the request bypassing the serializer. 2630 * @param contentType 2631 * The content type of the request. 2632 * @return 2633 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2634 * as a parsed object. 2635 * @throws RestCallException If any authentication errors occurred. 2636 */ 2637 public RestRequest patch(Object uri, String body, String contentType) throws RestCallException { 2638 return request("PATCH", uri, true).bodyString(body).contentType(contentType); 2639 } 2640 2641 /** 2642 * Same as {@link #patch(Object, Object)} but don't specify the input yet. 2643 * 2644 * <p> 2645 * You must call {@link RestRequest#body(Object)} to set the contents on the result object. 2646 * 2647 * @param uri 2648 * The URI of the remote REST resource. 2649 * <br>Can be any of the following types: 2650 * <ul> 2651 * <li>{@link URIBuilder} 2652 * <li>{@link URI} 2653 * <li>{@link URL} 2654 * <li>{@link String} 2655 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2656 * </ul> 2657 * @return 2658 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2659 * as a parsed object. 2660 * @throws RestCallException REST call failed. 2661 */ 2662 public RestRequest patch(Object uri) throws RestCallException { 2663 return request("PATCH", uri, true); 2664 } 2665 2666 2667 /** 2668 * Performs a REST call where the entire call is specified in a simple string. 2669 * 2670 * <p> 2671 * This method is useful for performing callbacks when the target of a callback is passed in 2672 * on an initial request, for example to signal when a long-running process has completed. 2673 * 2674 * <p> 2675 * The call string can be any of the following formats: 2676 * <ul class='spaced-list'> 2677 * <li> 2678 * <js>"[method] [uri]"</js> - e.g. <js>"GET http://localhost/callback"</js> 2679 * <li> 2680 * <js>"[method] [uri] [payload]"</js> - e.g. <js>"POST http://localhost/callback some text payload"</js> 2681 * <li> 2682 * <js>"[method] [headers] [uri] [payload]"</js> - e.g. <js>"POST {'Content-Type':'text/json'} http://localhost/callback {'some':'json'}"</js> 2683 * </ul> 2684 * <p> 2685 * The payload will always be sent using a simple {@link StringEntity}. 2686 * 2687 * @param callString The call string. 2688 * @return 2689 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2690 * as a parsed object. 2691 * @throws RestCallException REST call failed. 2692 */ 2693 public RestRequest callback(String callString) throws RestCallException { 2694 callString = emptyIfNull(callString); 2695 2696 // S01 - Looking for end of method. 2697 // S02 - Found end of method, looking for beginning of URI or headers. 2698 // S03 - Found beginning of headers, looking for end of headers. 2699 // S04 - Found end of headers, looking for beginning of URI. 2700 // S05 - Found beginning of URI, looking for end of URI. 2701 2702 StateMachineState state = S01; 2703 2704 int mark = 0; 2705 String method = null, headers = null, uri = null, content = null; 2706 for (int i = 0; i < callString.length(); i++) { 2707 char c = callString.charAt(i); 2708 if (state == S01) { 2709 if (isWhitespace(c)) { 2710 method = callString.substring(mark, i); 2711 state = S02; 2712 } 2713 } else if (state == S02) { 2714 if (! isWhitespace(c)) { 2715 mark = i; 2716 if (c == '{') 2717 state = S03; 2718 else 2719 state = S05; 2720 } 2721 } else if (state == S03) { 2722 if (c == '}') { 2723 headers = callString.substring(mark, i+1); 2724 state = S04; 2725 } 2726 } else if (state == S04) { 2727 if (! isWhitespace(c)) { 2728 mark = i; 2729 state = S05; 2730 } 2731 } else /* (state == S05) */ { 2732 if (isWhitespace(c)) { 2733 uri = callString.substring(mark, i); 2734 content = callString.substring(i).trim(); 2735 break; 2736 } 2737 } 2738 } 2739 2740 if (state != S05) 2741 throw new RestCallException(null, null, "Invalid format for call string. State={0}", state); 2742 2743 try { 2744 RestRequest req = request(method, uri, isNotEmpty(content)); 2745 if (headers != null) 2746 for (Map.Entry<String,Object> e : OMap.ofJson(headers).entrySet()) 2747 req.header(BasicHeader.of(e.getKey(), e.getValue())); 2748 if (isNotEmpty(content)) 2749 req.bodyString(content); 2750 return req; 2751 } catch (ParseException e) { 2752 throw new RestCallException(null, e, "Invalid format for call string."); 2753 } 2754 } 2755 2756 /** 2757 * Perform a generic REST call. 2758 * 2759 * @param method The HTTP method. 2760 * @param uri 2761 * The URI of the remote REST resource. 2762 * <br>Can be any of the following types: 2763 * <ul> 2764 * <li>{@link URIBuilder} 2765 * <li>{@link URI} 2766 * <li>{@link URL} 2767 * <li>{@link String} 2768 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2769 * </ul> 2770 * @param body 2771 * The HTTP body content. 2772 * Can be of the following types: 2773 * <ul class='spaced-list'> 2774 * <li> 2775 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 2776 * <li> 2777 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 2778 * <li> 2779 * {@link HttpResource}/{@link BasicHttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 2780 * <li> 2781 * {@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 2782 * <li> 2783 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 2784 * {@link RestClient}. 2785 * <li> 2786 * {@link NameValuePairSupplier} - Converted to a URL-encoded FORM post. 2787 * <li> 2788 * {@link Supplier} - A supplier of anything on this list. 2789 * </ul> 2790 * This parameter is IGNORED if the method type normally does not have content. 2791 * @return 2792 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2793 * as a parsed object. 2794 * @throws RestCallException If any authentication errors occurred. 2795 */ 2796 public RestRequest request(String method, Object uri, Object body) throws RestCallException { 2797 boolean b = hasContent(method); 2798 RestRequest rc = request(method, uri, b); 2799 if (b) 2800 rc.body(body); 2801 return rc; 2802 } 2803 2804 /** 2805 * Perform a generic REST call. 2806 * 2807 * @param method The HTTP method. 2808 * @param uri 2809 * The URI of the remote REST resource. 2810 * <br>Can be any of the following types: 2811 * <ul> 2812 * <li>{@link URIBuilder} 2813 * <li>{@link URI} 2814 * <li>{@link URL} 2815 * <li>{@link String} 2816 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2817 * </ul> 2818 * @return 2819 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2820 * as a parsed object. 2821 * @throws RestCallException If any authentication errors occurred. 2822 */ 2823 public RestRequest request(String method, Object uri) throws RestCallException { 2824 RestRequest rc = request(method, uri, hasContent(method)); 2825 return rc; 2826 } 2827 2828 /** 2829 * Perform a generic REST call. 2830 * 2831 * <p> 2832 * Typically you're going to use {@link #request(String, Object)} or {@link #request(String, Object, Object)}, 2833 * but this method is provided to allow you to perform non-standard HTTP methods (e.g. HTTP FOO). 2834 * 2835 * @param method The method name (e.g. <js>"GET"</js>, <js>"OPTIONS"</js>). 2836 * @param uri 2837 * The URI of the remote REST resource. 2838 * <br>Can be any of the following types: 2839 * <ul> 2840 * <li>{@link URIBuilder} 2841 * <li>{@link URI} 2842 * <li>{@link URL} 2843 * <li>{@link String} 2844 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 2845 * </ul> 2846 * @param hasBody Boolean flag indicating if the specified request has content associated with it. 2847 * @return 2848 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 2849 * as a parsed object. 2850 * @throws RestCallException If any authentication errors occurred. 2851 */ 2852 public RestRequest request(String method, Object uri, boolean hasBody) throws RestCallException { 2853 if (method == null) 2854 method = "GET"; 2855 if (isClosed) { 2856 Exception e2 = null; 2857 if (closedStack != null) { 2858 e2 = new Exception("Creation stack:"); 2859 e2.setStackTrace(closedStack); 2860 throw new RestCallException(null, e2, "RestClient.close() has already been called. This client cannot be reused."); 2861 } 2862 throw new RestCallException(null, null, "RestClient.close() has already been called. This client cannot be reused. Closed location stack trace can be displayed by setting the system property 'org.apache.juneau.rest.client2.RestClient.trackCreation' to true."); 2863 } 2864 2865 RestRequest req = createRequest(toURI(uri, rootUri), method.toUpperCase(Locale.ENGLISH), hasBody); 2866 2867 for (Object o : headers) 2868 req.header(BasicHeader.cast(o)); 2869 2870 for (Object o : query) 2871 req.query(BasicNameValuePair.cast(o)); 2872 2873 for (Object o : formData) 2874 req.formData(BasicNameValuePair.cast(o)); 2875 2876 onInit(req); 2877 2878 return req; 2879 } 2880 2881 /** 2882 * Creates a {@link RestRequest} object from the specified {@link HttpRequest} object. 2883 * 2884 * <p> 2885 * Subclasses can override this method to provide their own specialized {@link RestRequest} objects. 2886 * 2887 * @param uri The target. 2888 * @param method The HTTP method (uppercase). 2889 * @param hasBody Whether this method has a request entity. 2890 * @return A new {@link RestRequest} object. 2891 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt. 2892 */ 2893 protected RestRequest createRequest(URI uri, String method, boolean hasBody) throws RestCallException { 2894 return new RestRequest(this, uri, method, hasBody); 2895 } 2896 2897 /** 2898 * Creates a {@link RestResponse} object from the specified {@link HttpResponse} object. 2899 * 2900 * <p> 2901 * Subclasses can override this method to provide their own specialized {@link RestResponse} objects. 2902 * 2903 * @param request The request creating this response. 2904 * @param httpResponse The response object to wrap. 2905 * @param parser The parser to use to parse the response. 2906 * 2907 * @return A new {@link RestResponse} object. 2908 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt. 2909 */ 2910 protected RestResponse createResponse(RestRequest request, HttpResponse httpResponse, Parser parser) throws RestCallException { 2911 return new RestResponse(this, request, httpResponse, parser); 2912 } 2913 2914 /** 2915 * Create a new proxy interface against a 3rd-party REST interface. 2916 * 2917 * <p> 2918 * The URI to the REST interface is based on the following values: 2919 * <ul> 2920 * <li>The {@link Remote#path() @Remote(path)} annotation on the interface (<c>remote-path</c>). 2921 * <li>The {@link RestClientBuilder#rootUri(Object) rootUri} on the client (<c>root-url</c>). 2922 * <li>The fully-qualified class name of the interface (<c>class-name</c>). 2923 * </ul> 2924 * 2925 * <p> 2926 * The URI calculation is as follows: 2927 * <ul> 2928 * <li><c>remote-path</c> - If remote path is absolute. 2929 * <li><c>root-uri/remote-path</c> - If remote path is relative and root-uri has been specified. 2930 * <li><c>root-uri/class-name</c> - If remote path is not specified. 2931 * </ul> 2932 * 2933 * <p> 2934 * If the information is not available to resolve to an absolute URI, a {@link RemoteMetadataException} is thrown. 2935 * 2936 * <h5 class='section'>Examples:</h5> 2937 * <p class='bcode w800'> 2938 * <jk>package</jk> <jk>org.apache.foo</jk>; 2939 * 2940 * <ja>@RemoteResource</ja>(path=<js>"http://hostname/resturi/myinterface1"</js>) 2941 * <jk>public interface</jk> MyInterface1 { ... } 2942 * 2943 * <ja>@RemoteResource</ja>(path=<js>"/myinterface2"</js>) 2944 * <jk>public interface</jk> MyInterface2 { ... } 2945 * 2946 * <jk>public interface</jk> MyInterface3 { ... } 2947 * 2948 * <jc>// Resolves to "http://localhost/resturi/myinterface1"</jc> 2949 * MyInterface1 <jv>i1</jv> = RestClient 2950 * .<jsm>create</jsm>() 2951 * .build() 2952 * .getRemote(MyInterface1.<jk>class</jk>); 2953 * 2954 * <jc>// Resolves to "http://hostname/resturi/myinterface2"</jc> 2955 * MyInterface2 <jv>i2</jv> = RestClient 2956 * .<jsm>create</jsm>() 2957 * .rootUri(<js>"http://hostname/resturi"</js>) 2958 * .build() 2959 * .getRemote(MyInterface2.<jk>class</jk>); 2960 * 2961 * <jc>// Resolves to "http://hostname/resturi/org.apache.foo.MyInterface3"</jc> 2962 * MyInterface3 <jv>i3</jv> = RestClient 2963 * .<jsm>create</jsm>() 2964 * .rootUri(<js>"http://hostname/resturi"</js>) 2965 * .build() 2966 * .getRemote(MyInterface3.<jk>class</jk>); 2967 * </p> 2968 * 2969 * <ul class='notes'> 2970 * <li> 2971 * If you plan on using your proxy in a multi-threaded environment, you'll want to use an underlying 2972 * pooling client connection manager. 2973 * </ul> 2974 * 2975 * <ul class='seealso'> 2976 * <li class='link'>{@doc RestcProxies} 2977 * </ul> 2978 * 2979 * @param interfaceClass The interface to create a proxy for. 2980 * @return The new proxy interface. 2981 * @throws RemoteMetadataException If the REST URI cannot be determined based on the information given. 2982 */ 2983 public <T> T getRemote(Class<T> interfaceClass) { 2984 return getRemote(interfaceClass, null); 2985 } 2986 2987 /** 2988 * Same as {@link #getRemote(Class)} except explicitly specifies the URI of the REST interface. 2989 * 2990 * <ul class='seealso'> 2991 * <li class='link'>{@doc RestcProxies} 2992 * </ul> 2993 * 2994 * @param interfaceClass The interface to create a proxy for. 2995 * @param rootUri The URI of the REST interface. 2996 * @return The new proxy interface. 2997 */ 2998 public <T> T getRemote(Class<T> interfaceClass, Object rootUri) { 2999 return getRemote(interfaceClass, rootUri, null, null); 3000 } 3001 3002 /** 3003 * Same as {@link #getRemote(Class, Object)} but allows you to override the serializer and parser used. 3004 * 3005 * <ul class='seealso'> 3006 * <li class='link'>{@doc RestcProxies} 3007 * </ul> 3008 3009 * @param interfaceClass The interface to create a proxy for. 3010 * @param rootUri The URI of the REST interface. 3011 * @param serializer The serializer used to serialize POJOs to the body of the HTTP request. 3012 * @param parser The parser used to parse POJOs from the body of the HTTP response. 3013 * @return The new proxy interface. 3014 */ 3015 @SuppressWarnings({ "unchecked" }) 3016 public <T> T getRemote(final Class<T> interfaceClass, Object rootUri, final Serializer serializer, final Parser parser) { 3017 3018 if (rootUri == null) 3019 rootUri = this.rootUri; 3020 3021 final String restUrl2 = trimSlashes(emptyIfNull(rootUri)); 3022 3023 return (T)Proxy.newProxyInstance( 3024 interfaceClass.getClassLoader(), 3025 new Class[] { interfaceClass }, 3026 new InvocationHandler() { 3027 3028 final RemoteMeta rm = new RemoteMeta(interfaceClass); 3029 3030 @Override /* InvocationHandler */ 3031 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 3032 RemoteMethodMeta rmm = rm.getMethodMeta(method); 3033 3034 String uri = rmm.getFullPath(); 3035 if (uri.indexOf("://") == -1) 3036 uri = restUrl2 + '/' + uri; 3037 if (uri.indexOf("://") == -1) 3038 throw new RemoteMetadataException(interfaceClass, "Root URI has not been specified. Cannot construct absolute path to remote resource."); 3039 3040 String httpMethod = rmm.getHttpMethod(); 3041 HttpPartSerializerSession s = getPartSerializerSession(); 3042 3043 RestRequest rc = request(httpMethod, uri, hasContent(httpMethod)); 3044 3045 rc.serializer(serializer); 3046 rc.parser(parser); 3047 3048 for (Header h : rm.getHeaders()) 3049 rc.header(h); 3050 3051 for (RemoteMethodArg a : rmm.getPathArgs()) 3052 rc.pathArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); 3053 3054 for (RemoteMethodArg a : rmm.getQueryArgs()) 3055 rc.queryArg(a.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS, a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); 3056 3057 for (RemoteMethodArg a : rmm.getFormDataArgs()) 3058 rc.formDataArg(a.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS, a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); 3059 3060 for (RemoteMethodArg a : rmm.getHeaderArgs()) 3061 rc.headerArg(a.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS, a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); 3062 3063 RemoteMethodArg ba = rmm.getBodyArg(); 3064 if (ba != null) 3065 rc.body(args[ba.getIndex()], ba.getSchema()); 3066 3067 if (rmm.getRequestArgs().length > 0) { 3068 for (RemoteMethodBeanArg rmba : rmm.getRequestArgs()) { 3069 RequestBeanMeta rbm = rmba.getMeta(); 3070 Object bean = args[rmba.getIndex()]; 3071 if (bean != null) { 3072 for (RequestBeanPropertyMeta p : rbm.getProperties()) { 3073 Object val = p.getGetter().invoke(bean); 3074 HttpPartType pt = p.getPartType(); 3075 HttpPartSerializerSession ps = p.getSerializer(s); 3076 String pn = p.getPartName(); 3077 HttpPartSchema schema = p.getSchema(); 3078 EnumSet<AddFlag> flags = schema.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS; 3079 if (pt == PATH) 3080 rc.pathArg(pn, val, schema, p.getSerializer(s)); 3081 else if (val != null) { 3082 if (pt == QUERY) 3083 rc.queryArg(flags, pn, val, schema, ps); 3084 else if (pt == FORMDATA) 3085 rc.formDataArg(flags, pn, val, schema, ps); 3086 else if (pt == HEADER) 3087 rc.headerArg(flags, pn, val, schema, ps); 3088 else /* (pt == HttpPartType.BODY) */ 3089 rc.body(val, schema); 3090 } 3091 } 3092 } 3093 } 3094 } 3095 3096 RemoteMethodReturn rmr = rmm.getReturns(); 3097 if (rmr.isFuture()) { 3098 return getExecutorService().submit(new Callable<Object>() { 3099 @Override 3100 public Object call() throws Exception { 3101 try { 3102 return executeRemote(interfaceClass, rc, method, rmm); 3103 } catch (Exception e) { 3104 throw e; 3105 } catch (Throwable e) { 3106 throw new RuntimeException(e); 3107 } 3108 } 3109 }); 3110 } else if (rmr.isCompletableFuture()) { 3111 CompletableFuture<Object> cf = new CompletableFuture<>(); 3112 getExecutorService().submit(new Callable<Object>() { 3113 @Override 3114 public Object call() throws Exception { 3115 try { 3116 cf.complete(executeRemote(interfaceClass, rc, method, rmm)); 3117 } catch (Throwable e) { 3118 cf.completeExceptionally(e); 3119 } 3120 return null; 3121 } 3122 }); 3123 return cf; 3124 } 3125 3126 return executeRemote(interfaceClass, rc, method, rmm); 3127 } 3128 }); 3129 } 3130 3131 Object executeRemote(Class<?> interfaceClass, RestRequest rc, Method method, RemoteMethodMeta rmm) throws Throwable { 3132 RemoteMethodReturn rmr = rmm.getReturns(); 3133 3134 try { 3135 Object ret = null; 3136 RestResponse res = null; 3137 if (rmr.getReturnValue() == RemoteReturn.NONE) { 3138 res = rc.complete(); 3139 } else if (rmr.getReturnValue() == RemoteReturn.STATUS) { 3140 res = rc.complete(); 3141 int returnCode = res.getStatusCode(); 3142 Class<?> rt = method.getReturnType(); 3143 if (rt == Integer.class || rt == int.class) 3144 ret = returnCode; 3145 else if (rt == Boolean.class || rt == boolean.class) 3146 ret = returnCode < 400; 3147 else 3148 throw new RestCallException(res, null, "Invalid return type on method annotated with @RemoteMethod(returns=RemoteReturn.STATUS). Only integer and booleans types are valid."); 3149 } else if (rmr.getReturnValue() == RemoteReturn.BEAN) { 3150 rc.ignoreErrors(); 3151 res = rc.run(); 3152 ret = res.as(rmr.getResponseBeanMeta()); 3153 } else { 3154 Class<?> rt = method.getReturnType(); 3155 if (Throwable.class.isAssignableFrom(rt)) 3156 rc.ignoreErrors(); 3157 res = rc.run(); 3158 Object v = res.getBody().as(rmr.getReturnType()); 3159 if (v == null && rt.isPrimitive()) 3160 v = ClassInfo.of(rt).getPrimitiveDefault(); 3161 if (rt.getName().equals(res.getStringHeader("Exception-Name"))) 3162 res.removeHeaders("Exception-Name"); 3163 ret = v; 3164 } 3165 3166 ThrowableUtils.throwException(res.getStringHeader("Exception-Name"), res.getStringHeader("Exception-Message"), rmm.getExceptions()); 3167 return ret; 3168 } catch (RestCallException e) { 3169 ThrowableUtils.throwException(e.getServerExceptionName(), e.getServerExceptionMessage(), rmm.getExceptions()); 3170 throw new RuntimeException(e); 3171 } 3172 } 3173 3174 /** 3175 * Create a new proxy interface against an RRPC-style service. 3176 * 3177 * <p> 3178 * Remote interfaces are interfaces exposed on the server side using either the <c>RrpcServlet</c> 3179 * or <c>RRPC</c> REST methods. 3180 * 3181 * <p> 3182 * The URI to the REST interface is based on the following values: 3183 * <ul> 3184 * <li>The {@link Remote#path() @Remote(path)} annotation on the interface (<c>remote-path</c>). 3185 * <li>The {@link RestClientBuilder#rootUri(Object) rootUri} on the client (<c>root-url</c>). 3186 * <li>The fully-qualified class name of the interface (<c>class-name</c>). 3187 * </ul> 3188 * 3189 * <p> 3190 * The URI calculation is as follows: 3191 * <ul> 3192 * <li><c>remote-path</c> - If remote path is absolute. 3193 * <li><c>root-url/remote-path</c> - If remote path is relative and root-url has been specified. 3194 * <li><c>root-url/class-name</c> - If remote path is not specified. 3195 * </ul> 3196 * 3197 * <p> 3198 * If the information is not available to resolve to an absolute URI, a {@link RemoteMetadataException} is thrown. 3199 * 3200 * <ul class='notes'> 3201 * <li> 3202 * If you plan on using your proxy in a multi-threaded environment, you'll want to use an underlying 3203 * pooling client connection manager. 3204 * </ul> 3205 * 3206 * <ul class='seealso'> 3207 * <li class='link'>{@doc RestRpc} 3208 * </ul> 3209 * 3210 * @param interfaceClass The interface to create a proxy for. 3211 * @return The new proxy interface. 3212 * @throws RemoteMetadataException If the REST URI cannot be determined based on the information given. 3213 */ 3214 public <T> T getRrpcInterface(final Class<T> interfaceClass) { 3215 return getRrpcInterface(interfaceClass, null); 3216 } 3217 3218 /** 3219 * Same as {@link #getRrpcInterface(Class)} except explicitly specifies the URI of the REST interface. 3220 * 3221 * <ul class='seealso'> 3222 * <li class='link'>{@doc RestRpc} 3223 * </ul> 3224 * 3225 * @param interfaceClass The interface to create a proxy for. 3226 * @param uri The URI of the REST interface. 3227 * @return The new proxy interface. 3228 */ 3229 public <T> T getRrpcInterface(final Class<T> interfaceClass, final Object uri) { 3230 return getRrpcInterface(interfaceClass, uri, null, null); 3231 } 3232 3233 /** 3234 * Same as {@link #getRrpcInterface(Class, Object)} but allows you to override the serializer and parser used. 3235 * 3236 * <ul class='seealso'> 3237 * <li class='link'>{@doc RestRpc} 3238 * </ul> 3239 * 3240 * @param interfaceClass The interface to create a proxy for. 3241 * @param uri The URI of the REST interface. 3242 * @param serializer The serializer used to serialize POJOs to the body of the HTTP request. 3243 * @param parser The parser used to parse POJOs from the body of the HTTP response. 3244 * @return The new proxy interface. 3245 */ 3246 @SuppressWarnings({ "unchecked" }) 3247 public <T> T getRrpcInterface(final Class<T> interfaceClass, Object uri, final Serializer serializer, final Parser parser) { 3248 3249 if (uri == null) { 3250 RrpcInterfaceMeta rm = new RrpcInterfaceMeta(interfaceClass, ""); 3251 String path = rm.getPath(); 3252 if (path.indexOf("://") == -1) { 3253 if (isEmpty(rootUri)) 3254 throw new RemoteMetadataException(interfaceClass, "Root URI has not been specified. Cannot construct absolute path to remote interface."); 3255 path = trimSlashes(rootUri) + '/' + path; 3256 } 3257 uri = path; 3258 } 3259 3260 final String restUrl2 = stringify(uri); 3261 3262 return (T)Proxy.newProxyInstance( 3263 interfaceClass.getClassLoader(), 3264 new Class[] { interfaceClass }, 3265 new InvocationHandler() { 3266 3267 final RrpcInterfaceMeta rm = new RrpcInterfaceMeta(interfaceClass, restUrl2); 3268 3269 @Override /* InvocationHandler */ 3270 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 3271 RrpcInterfaceMethodMeta rim = rm.getMethodMeta(method); 3272 3273 String uri = rim.getUri(); 3274 3275 try { 3276 RestRequest rc = request("POST", uri, true).serializer(serializer).body(args); 3277 3278 Object v = rc.run().getBody().as(method.getGenericReturnType()); 3279 if (v == null && method.getReturnType().isPrimitive()) 3280 v = ClassInfo.of(method.getReturnType()).getPrimitiveDefault(); 3281 return v; 3282 3283 } catch (RestCallException e) { 3284 // Try to throw original exception if possible. 3285 ThrowableUtils.throwException(e.getServerExceptionName(), e.getServerExceptionMessage(), method.getExceptionTypes()); 3286 throw new RuntimeException(e); 3287 } 3288 } 3289 }); 3290 } 3291 3292 @Override 3293 protected void finalize() throws Throwable { 3294 if (leakDetection && ! isClosed && ! keepHttpClientOpen) { 3295 StringBuilder sb = new StringBuilder("WARNING: RestClient garbage collected before it was finalized."); // NOT DEBUG 3296 if (creationStack != null) { 3297 sb.append("\nCreation Stack:"); // NOT DEBUG 3298 for (StackTraceElement e : creationStack) 3299 sb.append("\n\t" + e); // NOT DEBUG 3300 } 3301 log(WARNING, sb.toString()); 3302 } 3303 } 3304 3305 /** 3306 * Logs a message. 3307 * 3308 * @param level The log level. 3309 * @param t Thrown exception. Can be <jk>null</jk>. 3310 * @param msg The message. 3311 * @param args Optional message arguments. 3312 */ 3313 protected void log(Level level, Throwable t, String msg, Object...args) { 3314 logger.log(level, t, msg(msg, args)); 3315 if (logToConsole) { 3316 console.println(msg(msg, args).get()); 3317 if (t != null) 3318 t.printStackTrace(console); 3319 } 3320 } 3321 3322 /** 3323 * Logs a message. 3324 * 3325 * @param level The log level. 3326 * @param msg The message with {@link MessageFormat}-style arguments. 3327 * @param args The arguments. 3328 */ 3329 protected void log(Level level, String msg, Object...args) { 3330 logger.log(level, msg(msg, args)); 3331 if (logToConsole) 3332 console.println(msg(msg, args).get()); 3333 } 3334 3335 private Supplier<String> msg(String msg, Object...args) { 3336 return ()->args.length == 0 ? msg : MessageFormat.format(msg, args); 3337 } 3338 3339 3340 //----------------------------------------------------------------------------------------------------------------- 3341 // RestCallInterceptor methods 3342 //----------------------------------------------------------------------------------------------------------------- 3343 3344 /** 3345 * Interceptor method called immediately after the RestRequest object is created and all headers/query/form-data has been copied from the client. 3346 * 3347 * <p> 3348 * Subclasses can override this method to intercept the request and perform special modifications. 3349 * 3350 * <ul class='seealso'> 3351 * <li class='jf'>{@link RestClient#RESTCLIENT_interceptors} 3352 * <li class='jm'>{@link RestClientBuilder#interceptors(Object...)} 3353 * </ul> 3354 * 3355 * @param req The HTTP request. 3356 * @throws RestCallException If any of the interceptors threw an exception. 3357 */ 3358 @Override 3359 public void onInit(RestRequest req) throws RestCallException { 3360 try { 3361 for (RestCallInterceptor rci : interceptors) 3362 rci.onInit(req); 3363 } catch (RuntimeException | RestCallException e) { 3364 throw e; 3365 } catch (Exception e) { 3366 throw new RestCallException(null, e, "Interceptor threw an exception on init."); 3367 } 3368 } 3369 3370 /** 3371 * Interceptor method called immediately after an HTTP response has been received. 3372 * 3373 * <p> 3374 * Subclasses can override this method to intercept the response and perform special modifications. 3375 * 3376 * <ul class='seealso'> 3377 * <li class='jf'>{@link RestClient#RESTCLIENT_interceptors} 3378 * <li class='jm'>{@link RestClientBuilder#interceptors(Object...)} 3379 * </ul> 3380 * 3381 * @param req The HTTP request. 3382 * @param res The HTTP response. 3383 * @throws RestCallException If any of the interceptors threw an exception. 3384 */ 3385 @Override 3386 public void onConnect(RestRequest req, RestResponse res) throws RestCallException { 3387 try { 3388 for (RestCallInterceptor rci : interceptors) 3389 rci.onConnect(req, res); 3390 } catch (RuntimeException | RestCallException e) { 3391 throw e; 3392 } catch (Exception e) { 3393 throw new RestCallException(res, e, "Interceptor threw an exception on connect."); 3394 } 3395 } 3396 3397 /** 3398 * Interceptor method called immediately after the RestRequest object is created and all headers/query/form-data has been set on the request from the client. 3399 * 3400 * <p> 3401 * Subclasses can override this method to handle any cleanup operations. 3402 * 3403 * <ul class='seealso'> 3404 * <li class='jf'>{@link RestClient#RESTCLIENT_interceptors} 3405 * <li class='jm'>{@link RestClientBuilder#interceptors(Object...)} 3406 * </ul> 3407 * 3408 * @param req The HTTP request. 3409 * @param res The HTTP response. 3410 * @throws RestCallException If any of the interceptors threw an exception. 3411 */ 3412 @Override 3413 public void onClose(RestRequest req, RestResponse res) throws RestCallException { 3414 try { 3415 for (RestCallInterceptor rci : interceptors) 3416 rci.onClose(req, res); 3417 } catch (RuntimeException | RestCallException e) { 3418 throw e; 3419 } catch (Exception e) { 3420 throw new RestCallException(res, e, "Interceptor threw an exception on close."); 3421 } 3422 } 3423 3424 //------------------------------------------------------------------------------------------------ 3425 // Passthrough methods for HttpClient. 3426 //------------------------------------------------------------------------------------------------ 3427 3428 /** 3429 * Obtains the parameters for this client. 3430 * 3431 * These parameters will become defaults for all requests being executed with this client, and for the parameters of dependent objects in this client. 3432 * 3433 * @return The default parameters. 3434 * @deprecated Use {@link RequestConfig}. 3435 */ 3436 @Deprecated 3437 @Override /* HttpClient */ 3438 public HttpParams getParams() { 3439 return httpClient.getParams(); 3440 } 3441 3442 /** 3443 * Obtains the connection manager used by this client. 3444 * 3445 * @return The connection manager. 3446 * @deprecated Use {@link HttpClientBuilder}. 3447 */ 3448 @Deprecated 3449 @Override /* HttpClient */ 3450 public ClientConnectionManager getConnectionManager() { 3451 return httpClient.getConnectionManager(); 3452 } 3453 3454 /** 3455 * Executes HTTP request using the default context. 3456 * 3457 * <ul class='notes'> 3458 * <li>This method gets passed on directly to the underlying {@link HttpClient} class. 3459 * </ul> 3460 * 3461 * @param request The request to execute. 3462 * @return 3463 * The response to the request. 3464 * <br>This is always a final response, never an intermediate response with an 1xx status code. 3465 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 3466 * implementation and configuration of this client. 3467 * @throws IOException In case of a problem or the connection was aborted. 3468 * @throws ClientProtocolException In case of an http protocol error. 3469 */ 3470 @Override /* HttpClient */ 3471 public HttpResponse execute(HttpUriRequest request) throws IOException, ClientProtocolException { 3472 return httpClient.execute(request); 3473 } 3474 3475 /** 3476 * Executes HTTP request using the given context. 3477 * 3478 * <ul class='notes'> 3479 * <li>This method gets passed on directly to the underlying {@link HttpClient} class. 3480 * </ul> 3481 * 3482 * @param request The request to execute. 3483 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 3484 * @return 3485 * The response to the request. 3486 * <br>This is always a final response, never an intermediate response with an 1xx status code. 3487 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 3488 * implementation and configuration of this client. 3489 * @throws IOException In case of a problem or the connection was aborted. 3490 * @throws ClientProtocolException In case of an http protocol error. 3491 */ 3492 @Override /* HttpClient */ 3493 public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException, ClientProtocolException { 3494 return httpClient.execute(request, context); 3495 } 3496 3497 /** 3498 * Executes HTTP request using the default context. 3499 * 3500 * <ul class='notes'> 3501 * <li>This method gets passed on directly to the underlying {@link HttpClient} class. 3502 * </ul> 3503 * 3504 * @param target The target host for the request. 3505 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default 3506 * target or by inspecting the request. 3507 * @param request The request to execute. 3508 * @return The response to the request. 3509 * <br>This is always a final response, never an intermediate response with an 1xx status code. 3510 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 3511 * implementation and configuration of this client. 3512 * @throws IOException In case of a problem or the connection was aborted. 3513 * @throws ClientProtocolException In case of an http protocol error. 3514 */ 3515 @Override /* HttpClient */ 3516 public HttpResponse execute(HttpHost target, HttpRequest request) throws IOException, ClientProtocolException { 3517 return httpClient.execute(target, request); 3518 } 3519 3520 /** 3521 * Executes HTTP request using the given context. 3522 * 3523 * <ul class='notes'> 3524 * <li>This method gets passed on directly to the underlying {@link HttpClient} class. 3525 * <li>The {@link #run(HttpHost,HttpRequest,HttpContext)} method has been provided as a wrapper around this method. 3526 * Subclasses can override these methods for handling requests with and without bodies separately. 3527 * <li>The {@link RestCallHandler} interface can also be implemented to intercept this method. 3528 * </ul> 3529 * 3530 * @param target The target host for the request. 3531 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default 3532 * target or by inspecting the request. 3533 * @param request The request to execute. 3534 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 3535 * @return 3536 * The response to the request. 3537 * <br>This is always a final response, never an intermediate response with an 1xx status code. 3538 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 3539 * implementation and configuration of this client. 3540 * @throws IOException In case of a problem or the connection was aborted. 3541 * @throws ClientProtocolException In case of an http protocol error. 3542 */ 3543 @Override /* HttpClient */ 3544 public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException, ClientProtocolException { 3545 return httpClient.execute(target, request, context); 3546 } 3547 3548 /** 3549 * Executes HTTP request using the default context and processes the response using the given response handler. 3550 * 3551 * <p> 3552 * The content entity associated with the response is fully consumed and the underlying connection is released back 3553 * to the connection manager automatically in all cases relieving individual {@link ResponseHandler ResponseHandlers} 3554 * from having to manage resource deallocation internally. 3555 * 3556 * <ul class='notes'> 3557 * <li>This method gets passed on directly to the underlying {@link HttpClient} class. 3558 * </ul> 3559 * 3560 * @param request The request to execute. 3561 * @param responseHandler The response handler. 3562 * @return Object returned by response handler. 3563 * @throws IOException In case of a problem or the connection was aborted. 3564 * @throws ClientProtocolException In case of an http protocol error. 3565 */ 3566 @Override /* HttpClient */ 3567 public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler) throws IOException, ClientProtocolException { 3568 return httpClient.execute(request, responseHandler); 3569 } 3570 3571 /** 3572 * Executes HTTP request using the given context and processes the response using the given response handler. 3573 * 3574 * <p> 3575 * The content entity associated with the response is fully consumed and the underlying connection is released back 3576 * to the connection manager automatically in all cases relieving individual {@link ResponseHandler ResponseHandlers} 3577 * from having to manage resource deallocation internally. 3578 * 3579 * <ul class='notes'> 3580 * <li>This method gets passed on directly to the underlying {@link HttpClient} class. 3581 * </ul> 3582 * 3583 * @param request The request to execute. 3584 * @param responseHandler The response handler. 3585 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 3586 * @return The response object as generated by the response handler. 3587 * @throws IOException In case of a problem or the connection was aborted. 3588 * @throws ClientProtocolException In case of an http protocol error. 3589 */ 3590 @Override /* HttpClient */ 3591 public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context) throws IOException, ClientProtocolException { 3592 return httpClient.execute(request, responseHandler, context); 3593 } 3594 3595 /** 3596 * Executes HTTP request to the target using the default context and processes the response using the given response handler. 3597 * 3598 * <p> 3599 * The content entity associated with the response is fully consumed and the underlying connection is released back 3600 * to the connection manager automatically in all cases relieving individual {@link ResponseHandler ResponseHandlers} 3601 * from having to manage resource deallocation internally. 3602 * 3603 * <ul class='notes'> 3604 * <li>This method gets passed on directly to the underlying {@link HttpClient} class. 3605 * </ul> 3606 * 3607 * @param target 3608 * The target host for the request. 3609 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default target or by inspecting the request. 3610 * @param request The request to execute. 3611 * @param responseHandler The response handler. 3612 * @return The response object as generated by the response handler. 3613 * @throws IOException In case of a problem or the connection was aborted. 3614 * @throws ClientProtocolException In case of an http protocol error. 3615 */ 3616 @Override /* HttpClient */ 3617 public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler) throws IOException, ClientProtocolException { 3618 return httpClient.execute(target, request, responseHandler); 3619 } 3620 3621 /** 3622 * Executes a request using the default context and processes the response using the given response handler. 3623 * 3624 * <p> 3625 * The content entity associated with the response is fully consumed and the underlying connection is released back 3626 * to the connection manager automatically in all cases relieving individual {@link ResponseHandler ResponseHandlers} 3627 * from having to manage resource deallocation internally. 3628 * 3629 * <ul class='notes'> 3630 * <li>This method gets passed on directly to the underlying {@link HttpClient} class. 3631 * </ul> 3632 * 3633 * @param target 3634 * The target host for the request. 3635 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default target or by inspecting the request. 3636 * @param request The request to execute. 3637 * @param responseHandler The response handler. 3638 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 3639 * @return The response object as generated by the response handler. 3640 * @throws IOException In case of a problem or the connection was aborted. 3641 * @throws ClientProtocolException In case of an http protocol error. 3642 */ 3643 @Override /* HttpClient */ 3644 public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context) throws IOException, ClientProtocolException { 3645 return httpClient.execute(target, request, responseHandler, context); 3646 } 3647 3648 //----------------------------------------------------------------------------------------------------------------- 3649 // Other methods. 3650 //----------------------------------------------------------------------------------------------------------------- 3651 3652 HttpPartSerializerSession getPartSerializerSession() { 3653 return partSerializer.createPartSession(null); 3654 } 3655 3656 HttpPartParserSession getPartParserSession() { 3657 return partParser.createPartSession(null); 3658 } 3659 3660 private Pattern absUrlPattern = Pattern.compile("^\\w+\\:\\/\\/.*"); 3661 3662 URI toURI(Object x, String rootUri) throws RestCallException { 3663 try { 3664 if (x instanceof URI) 3665 return (URI)x; 3666 if (x instanceof URL) 3667 ((URL)x).toURI(); 3668 if (x instanceof URIBuilder) 3669 return ((URIBuilder)x).build(); 3670 String s = x == null ? "" : x.toString(); 3671 if (rootUri != null && ! absUrlPattern.matcher(s).matches()) { 3672 if (s.isEmpty()) 3673 s = rootUri; 3674 else { 3675 StringBuilder sb = new StringBuilder(rootUri); 3676 if (! s.startsWith("/")) 3677 sb.append('/'); 3678 sb.append(s); 3679 s = sb.toString(); 3680 } 3681 } 3682 s = fixUrl(s); 3683 return new URI(s); 3684 } catch (URISyntaxException e) { 3685 throw new RestCallException(null, e, "Invalid URI encountered: {0}", x); // Shouldn't happen. 3686 } 3687 } 3688 3689 ExecutorService getExecutorService() { 3690 if (executorService != null) 3691 return executorService; 3692 synchronized(this) { 3693 executorService = new ThreadPoolExecutor(1, 1, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)); 3694 return executorService; 3695 } 3696 } 3697 3698 /* 3699 * Returns the serializer that best matches the specified content type. 3700 * If no match found or the content type is null, returns the serializer in the list if it's a list of one. 3701 * Returns null if no serializers are defined. 3702 */ 3703 Serializer getMatchingSerializer(String mediaType) { 3704 if (serializers.isEmpty()) 3705 return null; 3706 if (mediaType != null) { 3707 Serializer s = serializers.getSerializer(mediaType); 3708 if (s != null) 3709 return s; 3710 } 3711 List<Serializer> l = serializers.getSerializers(); 3712 return l.size() == 1 ? l.get(0) : null; 3713 } 3714 3715 /* 3716 * Returns the parser that best matches the specified content type. 3717 * If no match found or the content type is null, returns the parser in the list if it's a list of one. 3718 * Returns null if no parsers are defined. 3719 */ 3720 Parser getMatchingParser(String mediaType) { 3721 if (parsers.isEmpty()) 3722 return null; 3723 if (mediaType != null) { 3724 Parser p = parsers.getParser(mediaType); 3725 if (p != null) 3726 return p; 3727 } 3728 List<Parser> l = parsers.getParsers(); 3729 return l.size() == 1 ? l.get(0) : null; 3730 } 3731 3732 @SuppressWarnings("unchecked") 3733 <T extends Context> T getInstance(Class<T> c) { 3734 Context o = requestContexts.get(c); 3735 if (o == null) { 3736 o = ContextCache.INSTANCE.create(c, getPropertyStore()); 3737 requestContexts.put(c, o); 3738 } 3739 return (T)o; 3740 } 3741 3742 @Override /* Context */ 3743 public OMap toMap() { 3744 return super.toMap() 3745 .a("RestClient", new DefaultFilteringOMap() 3746 .a("errorCodes", errorCodes) 3747 .a("executorService", executorService) 3748 .a("executorServiceShutdownOnClose", executorServiceShutdownOnClose) 3749 .a("headers", headers) 3750 .a("interceptors", interceptors) 3751 .a("keepHttpClientOpen", keepHttpClientOpen) 3752 .a("partParser", partParser) 3753 .a("partSerializer", partSerializer) 3754 .a("query", query) 3755 .a("rootUri", rootUri) 3756 ); 3757 } 3758}