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.internal.ClassUtils.*; 017import static org.apache.juneau.AddFlag.*; 018import static org.apache.juneau.httppart.HttpPartType.*; 019 020import java.io.*; 021import java.lang.reflect.*; 022import java.net.*; 023import java.text.*; 024import java.util.*; 025import java.util.concurrent.*; 026import java.util.function.*; 027import java.util.logging.*; 028 029import org.apache.http.*; 030import org.apache.http.client.config.*; 031import org.apache.http.client.entity.*; 032import org.apache.http.client.methods.*; 033import org.apache.http.client.utils.*; 034import org.apache.http.concurrent.*; 035import org.apache.http.entity.*; 036import org.apache.http.entity.BasicHttpEntity; 037import org.apache.http.entity.ContentType; 038import org.apache.http.params.*; 039import org.apache.http.protocol.*; 040import org.apache.juneau.*; 041import org.apache.juneau.collections.*; 042import org.apache.juneau.html.*; 043import org.apache.juneau.http.*; 044import org.apache.juneau.http.header.*; 045import org.apache.juneau.httppart.*; 046import org.apache.juneau.internal.*; 047import org.apache.juneau.json.*; 048import org.apache.juneau.msgpack.*; 049import org.apache.juneau.oapi.*; 050import org.apache.juneau.parser.*; 051import org.apache.juneau.plaintext.*; 052import org.apache.juneau.serializer.*; 053import org.apache.juneau.uon.*; 054import org.apache.juneau.urlencoding.*; 055import org.apache.juneau.xml.*; 056 057/** 058 * Represents a request to a remote REST resource. 059 * 060 * <p> 061 * Instances of this class are created by the various creator methods on the {@link RestClient} class. 062 * 063 * <ul class='seealso'> 064 * <li class='jc'>{@link RestClient} 065 * <li class='link'>{@doc juneau-rest-client} 066 * </ul> 067 */ 068public class RestRequest extends BeanSession implements HttpUriRequest, Configurable { 069 070 private static final ContentType TEXT_PLAIN = ContentType.create("text/plain"); 071 072 private final RestClient client; // The client that created this call. 073 private final HttpRequestBase request; // The request. 074 private RestResponse response; // The response. 075 List<RestCallInterceptor> interceptors = new ArrayList<>(); // Used for intercepting and altering requests. 076 077 private boolean ignoreErrors; 078 079 private Object input; 080 private boolean hasInput; // input() was called, even if it's setting 'null'. 081 private Serializer serializer; 082 private Parser parser; 083 private HttpPartSerializerSession partSerializer; 084 private HttpPartSchema requestBodySchema; 085 private URIBuilder uriBuilder; 086 private List<NameValuePair> formData; 087 private Predicate<Integer> errorCodes; 088 private HttpHost target; 089 private HttpContext context; 090 091 /** 092 * Constructs a REST call with the specified method name. 093 * 094 * @param client The client that created this request. 095 * @param uri The target URI. 096 * @param method The HTTP method name (uppercase). 097 * @param hasBody Whether this method has a body. 098 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt. 099 */ 100 protected RestRequest(RestClient client, URI uri, String method, boolean hasBody) throws RestCallException { 101 super(client, BeanSessionArgs.DEFAULT); 102 this.client = client; 103 this.request = createInnerRequest(method, uri, hasBody); 104 this.errorCodes = client.errorCodes; 105 this.partSerializer = client.getPartSerializerSession(); 106 this.uriBuilder = new URIBuilder(request.getURI()); 107 this.ignoreErrors = client.ignoreErrors; 108 } 109 110 /** 111 * Constructs the {@link HttpRequestBase} object that ends up being passed to the client execute method. 112 * 113 * <p> 114 * Subclasses can override this method to create their own request base objects. 115 * 116 * @param method The HTTP method. 117 * @param uri The HTTP URI. 118 * @param hasBody Whether the HTTP request has a body. 119 * @return A new {@link HttpRequestBase} object. 120 */ 121 protected HttpRequestBase createInnerRequest(String method, URI uri, boolean hasBody) { 122 HttpRequestBase req = hasBody ? new BasicHttpEntityRequestBase(this, method) : new BasicHttpRequestBase(this, method); 123 req.setURI(uri); 124 return req; 125 } 126 127 128 //------------------------------------------------------------------------------------------------------------------ 129 // Configuration 130 //------------------------------------------------------------------------------------------------------------------ 131 132 /** 133 * Convenience method for specifying JSON as the marshalling transmission media type for this request only. 134 * 135 * <p> 136 * {@link JsonSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 137 * <ul> 138 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 139 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 140 * </ul> 141 * <p> 142 * {@link JsonParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 143 * <ul> 144 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 145 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 146 * </ul> 147 * <p> 148 * <c>Accept</c> request header will be set to <js>"application/json"</js> unless overridden 149 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 150 * <p> 151 * <c>Content-Type</c> request header will be set to <js>"application/json"</js> unless overridden 152 * {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 153 * <p> 154 * Identical to calling <c>serializer(JsonSerializer.<jk>class</jk>).parser(JsonParser.<jk>class</jk>)</c>. 155 * 156 * @return This object (for method chaining). 157 */ 158 public RestRequest json() { 159 return serializer(JsonSerializer.class).parser(JsonParser.class); 160 } 161 162 /** 163 * Convenience method for specifying Simplified JSON as the marshalling transmission media type for this request only. 164 * 165 * <p> 166 * Simplified JSON is typically useful for automated tests because you can do simple string comparison of results 167 * without having to escape lots of quotes. 168 * 169 * <p> 170 * {@link SimpleJsonSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 171 * <ul> 172 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 173 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 174 * </ul> 175 * <p> 176 * {@link JsonParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 177 * <ul> 178 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 179 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 180 * </ul> 181 * <p> 182 * <c>Accept</c> request header will be set to <js>"application/json"</js> unless overridden 183 * by {@link #header(String,Object)} or {@link #accept(Object)}, or per-request via {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 184 * <p> 185 * <c>Content-Type</c> request header will be set to <js>"application/json+simple"</js> unless overridden 186 * by {@link #header(String,Object)} or {@link #contentType(Object)}, or per-request via {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 187 * <p> 188 * Can be combined with other marshaller setters such as {@link #xml()} to provide support for multiple languages. 189 * <ul> 190 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 191 * last-enabled language if the headers are not set. 192 * </ul> 193 * <p> 194 * Identical to calling <c>serializer(SimpleJsonSerializer.<jk>class</jk>).parser(JsonParser.<jk>class</jk>)</c>. 195 * 196 * <h5 class='section'>Example:</h5> 197 * <p class='bcode w800'> 198 * <jc>// Construct a client that uses Simplified JSON marshalling.</jc> 199 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build(); 200 * </p> 201 * 202 * @return This object (for method chaining). 203 */ 204 public RestRequest simpleJson() { 205 return serializer(SimpleJsonSerializer.class).parser(SimpleJsonParser.class); 206 } 207 208 /** 209 * Convenience method for specifying XML as the marshalling transmission media type for this request only. 210 * 211 * <p> 212 * {@link XmlSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 213 * <ul> 214 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 215 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 216 * </ul> 217 * <p> 218 * {@link XmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 219 * <ul> 220 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 221 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 222 * </ul> 223 * <p> 224 * <c>Accept</c> request header will be set to <js>"text/xml"</js> unless overridden 225 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 226 * <p> 227 * <c>Content-Type</c> request header will be set to <js>"text/xml"</js> unless overridden 228 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 229 * <p> 230 * Identical to calling <c>serializer(XmlSerializer.<jk>class</jk>).parser(XmlParser.<jk>class</jk>)</c>. 231 * 232 * <h5 class='section'>Example:</h5> 233 * <p class='bcode w800'> 234 * <jc>// Construct a client that uses XML marshalling.</jc> 235 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().xml().build(); 236 * </p> 237 * 238 * @return This object (for method chaining). 239 */ 240 public RestRequest xml() { 241 return serializer(XmlSerializer.class).parser(XmlParser.class); 242 } 243 244 /** 245 * Convenience method for specifying HTML as the marshalling transmission media type for this request only. 246 * 247 * <p> 248 * POJOs are converted to HTML without any sort of doc wrappers. 249 * 250 * <p> 251 * {@link HtmlSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 252 * <ul> 253 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 254 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 255 * </ul> 256 * <p> 257 * {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 258 * <ul> 259 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 260 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 261 * </ul> 262 * <p> 263 * <c>Accept</c> request header will be set to <js>"text/html"</js> unless overridden 264 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 265 * <p> 266 * <c>Content-Type</c> request header will be set to <js>"text/html"</js> unless overridden 267 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 268 * <p> 269 * Identical to calling <c>serializer(HtmlSerializer.<jk>class</jk>).parser(HtmlParser.<jk>class</jk>)</c>. 270 * 271 * <h5 class='section'>Example:</h5> 272 * <p class='bcode w800'> 273 * <jc>// Construct a client that uses HTML marshalling.</jc> 274 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().html().build(); 275 * </p> 276 * 277 * @return This object (for method chaining). 278 */ 279 public RestRequest html() { 280 return serializer(HtmlSerializer.class).parser(HtmlParser.class); 281 } 282 283 /** 284 * Convenience method for specifying HTML DOC as the marshalling transmission media type for this request only. 285 * 286 * <p> 287 * POJOs are converted to fully renderable HTML pages. 288 * 289 * <p> 290 * {@link HtmlDocSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 291 * <ul> 292 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 293 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 294 * </ul> 295 * <p> 296 * {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 297 * <ul> 298 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 299 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 300 * </ul> 301 * <p> 302 * <c>Accept</c> request header will be set to <js>"text/html"</js> unless overridden 303 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 304 * <p> 305 * <c>Content-Type</c> request header will be set to <js>"text/html"</js> unless overridden 306 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 307 * <p> 308 * Identical to calling <c>serializer(HtmlDocSerializer.<jk>class</jk>).parser(HtmlParser.<jk>class</jk>)</c>. 309 * 310 * <h5 class='section'>Example:</h5> 311 * <p class='bcode w800'> 312 * <jc>// Construct a client that uses HTML Doc marshalling.</jc> 313 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().htmlDoc().build(); 314 * </p> 315 * 316 * @return This object (for method chaining). 317 */ 318 public RestRequest htmlDoc() { 319 return serializer(HtmlDocSerializer.class).parser(HtmlParser.class); 320 } 321 322 /** 323 * Convenience method for specifying Stripped HTML DOC as the marshalling transmission media type for this request only. 324 * 325 * <p> 326 * Same as {@link #htmlDoc()} but without the header and body tags and page title and description. 327 * 328 * <p> 329 * {@link HtmlStrippedDocSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 330 * <ul> 331 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 332 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 333 * </ul> 334 * <p> 335 * {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 336 * <ul> 337 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 338 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 339 * </ul> 340 * <p> 341 * <c>Accept</c> request header will be set to <js>"text/html+stripped"</js> unless overridden 342 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 343 * <p> 344 * <c>Content-Type</c> request header will be set to <js>"text/html+stripped"</js> unless overridden 345 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 346 * <p> 347 * Identical to calling <c>serializer(HtmlStrippedDocSerializer.<jk>class</jk>).parser(HtmlParser.<jk>class</jk>)</c>. 348 * 349 * <h5 class='section'>Example:</h5> 350 * <p class='bcode w800'> 351 * <jc>// Construct a client that uses HTML Stripped Doc marshalling.</jc> 352 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().htmlStrippedDoc().build(); 353 * </p> 354 * 355 * @return This object (for method chaining). 356 */ 357 public RestRequest htmlStrippedDoc() { 358 return serializer(HtmlStrippedDocSerializer.class).parser(HtmlParser.class); 359 } 360 361 /** 362 * Convenience method for specifying Plain Text as the marshalling transmission media type for this request only. 363 * 364 * <p> 365 * Plain text marshalling typically only works on simple POJOs that can be converted to and from strings using 366 * swaps, swap methods, etc... 367 * 368 * <p> 369 * {@link PlainTextSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 370 * <ul> 371 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 372 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 373 * </ul> 374 * <p> 375 * {@link PlainTextParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 376 * <ul> 377 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 378 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 379 * </ul> 380 * <p> 381 * <c>Accept</c> request header will be set to <js>"text/plain"</js> unless overridden 382 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 383 * <p> 384 * <c>Content-Type</c> request header will be set to <js>"text/plain"</js> unless overridden 385 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 386 * <p> 387 * Identical to calling <c>serializer(PlainTextSerializer.<jk>class</jk>).parser(PlainTextParser.<jk>class</jk>)</c>. 388 * 389 * <h5 class='section'>Example:</h5> 390 * <p class='bcode w800'> 391 * <jc>// Construct a client that uses Plain Text marshalling.</jc> 392 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().plainText().build(); 393 * </p> 394 * 395 * @return This object (for method chaining). 396 */ 397 public RestRequest plainText() { 398 return serializer(PlainTextSerializer.class).parser(PlainTextParser.class); 399 } 400 401 /** 402 * Convenience method for specifying MessagePack as the marshalling transmission media type for this request only. 403 * 404 * <p> 405 * MessagePack is a binary equivalent to JSON that takes up considerably less space than JSON. 406 * 407 * <p> 408 * {@link MsgPackSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 409 * <ul> 410 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 411 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 412 * </ul> 413 * <p> 414 * {@link MsgPackParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 415 * <ul> 416 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 417 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 418 * </ul> 419 * <p> 420 * <c>Accept</c> request header will be set to <js>"octal/msgpack"</js> unless overridden 421 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 422 * <p> 423 * <c>Content-Type</c> request header will be set to <js>"octal/msgpack"</js> unless overridden 424 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 425 * <p> 426 * Identical to calling <c>serializer(MsgPackSerializer.<jk>class</jk>).parser(MsgPackParser.<jk>class</jk>)</c>. 427 * 428 * <h5 class='section'>Example:</h5> 429 * <p class='bcode w800'> 430 * <jc>// Construct a client that uses MessagePack marshalling.</jc> 431 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().msgPack().build(); 432 * </p> 433 * 434 * @return This object (for method chaining). 435 */ 436 public RestRequest msgPack() { 437 return serializer(MsgPackSerializer.class).parser(MsgPackParser.class); 438 } 439 440 /** 441 * Convenience method for specifying UON as the marshalling transmission media type for this request only. 442 * 443 * <p> 444 * UON is Url-Encoding Object notation that is equivalent to JSON but suitable for transmission as URL-encoded 445 * query and form post values. 446 * 447 * <p> 448 * {@link UonSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 449 * <ul> 450 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 451 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 452 * </ul> 453 * <p> 454 * {@link UonParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 455 * <ul> 456 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 457 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 458 * </ul> 459 * <p> 460 * <c>Accept</c> request header will be set to <js>"text/uon"</js> unless overridden 461 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 462 * <p> 463 * <c>Content-Type</c> request header will be set to <js>"text/uon"</js> unless overridden 464 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 465 * <p> 466 * Identical to calling <c>serializer(UonSerializer.<jk>class</jk>).parser(UonParser.<jk>class</jk>)</c>. 467 * 468 * <h5 class='section'>Example:</h5> 469 * <p class='bcode w800'> 470 * <jc>// Construct a client that uses UON marshalling.</jc> 471 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().uon().build(); 472 * </p> 473 * 474 * @return This object (for method chaining). 475 */ 476 public RestRequest uon() { 477 return serializer(UonSerializer.class).parser(UonParser.class); 478 } 479 480 /** 481 * Convenience method for specifying URL-Encoding as the marshalling transmission media type for this request only. 482 * 483 * <p> 484 * {@link UrlEncodingSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 485 * <ul> 486 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 487 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 488 * <li>This serializer is NOT used when using the {@link RestRequest#formData(String, Object)} (and related) methods for constructing 489 * the request body. Instead, the part serializer specified via {@link RestClientBuilder#partSerializer(Class)} is used. 490 * </ul> 491 * <p> 492 * {@link UrlEncodingParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 493 * <ul> 494 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 495 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 496 * </ul> 497 * <p> 498 * <c>Accept</c> request header will be set to <js>"application/x-www-form-urlencoded"</js> unless overridden 499 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 500 * <p> 501 * <c>Content-Type</c> request header will be set to <js>"application/x-www-form-urlencoded"</js> unless overridden 502 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 503 * <p> 504 * Identical to calling <c>serializer(UrlEncodingSerializer.<jk>class</jk>).parser(UrlEncodingParser.<jk>class</jk>)</c>. 505 * 506 * <h5 class='section'>Example:</h5> 507 * <p class='bcode w800'> 508 * <jc>// Construct a client that uses URL-Encoded marshalling.</jc> 509 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().urlEnc().build(); 510 * </p> 511 * 512 * @return This object (for method chaining). 513 */ 514 public RestRequest urlEnc() { 515 return serializer(UrlEncodingSerializer.class).parser(UrlEncodingParser.class); 516 } 517 518 /** 519 * Convenience method for specifying OpenAPI as the marshalling transmission media type for this request only. 520 * 521 * <p> 522 * OpenAPI is a language that allows serialization to formats that use {@link HttpPartSchema} objects to describe their structure. 523 * 524 * <p> 525 * {@link OpenApiSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 526 * <ul> 527 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 528 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 529 * <li>Typically the {@link RestRequest#body(Object, HttpPartSchema)} method will be used to specify the body of the request with the 530 * schema describing it's structure. 531 * </ul> 532 * <p> 533 * {@link OpenApiParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 534 * <ul> 535 * <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 536 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 537 * <li>Typically the {@link RestResponseBody#schema(HttpPartSchema)} method will be used to specify the structure of the response body. 538 * </ul> 539 * <p> 540 * <c>Accept</c> request header will be set to <js>"text/openapi"</js> unless overridden 541 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(Object)}. 542 * <p> 543 * <c>Content-Type</c> request header will be set to <js>"text/openapi"</js> unless overridden 544 * by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(Object)}. 545 * <p> 546 * Identical to calling <c>serializer(OpenApiSerializer.<jk>class</jk>).parser(OpenApiParser.<jk>class</jk>)</c>. 547 * 548 * <h5 class='section'>Example:</h5> 549 * <p class='bcode w800'> 550 * <jc>// Construct a client that uses OpenAPI marshalling.</jc> 551 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().openApi().build(); 552 * </p> 553 * 554 * @return This object (for method chaining). 555 */ 556 public RestRequest openApi() { 557 return serializer(OpenApiSerializer.class).parser(OpenApiParser.class); 558 } 559 560 /** 561 * Specifies the serializer to use on the request body. 562 * 563 * <p> 564 * Overrides the serializers specified on the {@link RestClient}. 565 * 566 * <p> 567 * The serializer is not modified by an of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 568 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 569 * 570 * <p> 571 * If the <c>Content-Type</c> header is not set on the request, it will be set to the media type of this serializer. 572 * 573 * @param serializer The serializer used to serialize POJOs to the body of the HTTP request. 574 * @return This object (for method chaining). 575 */ 576 public RestRequest serializer(Serializer serializer) { 577 this.serializer = serializer; 578 return this; 579 } 580 581 /** 582 * Specifies the serializer to use on the request body. 583 * 584 * <p> 585 * Overrides the serializers specified on the {@link RestClient}. 586 * 587 * <p> 588 * The serializer can be configured using any of the serializer property setters (e.g. {@link RestClientBuilder#sortCollections()}), 589 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 590 * 591 * <p> 592 * If the <c>Content-Type</c> header is not set on the request, it will be set to the media type of this serializer. 593 * 594 * @param serializer The serializer used to serialize POJOs to the body of the HTTP request. 595 * @return This object (for method chaining). 596 */ 597 public RestRequest serializer(Class<? extends Serializer> serializer) { 598 this.serializer = client.getInstance(serializer); 599 return this; 600 } 601 602 /** 603 * Specifies the parser to use on the response body. 604 * 605 * <p> 606 * Overrides the parsers specified on the {@link RestClient}. 607 * 608 * <p> 609 * The parser is not modified by any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 610 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 611 * 612 * <p> 613 * If the <c>Accept</c> header is not set on the request, it will be set to the media type of this parser. 614 * 615 * @param parser The parser used to parse POJOs from the body of the HTTP response. 616 * @return This object (for method chaining). 617 */ 618 public RestRequest parser(Parser parser) { 619 this.parser = parser; 620 return this; 621 } 622 623 /** 624 * Specifies the parser to use on the response body. 625 * 626 * <p> 627 * Overrides the parsers specified on the {@link RestClient}. 628 * 629 * <p> 630 * The parser can be configured using any of the parser property setters (e.g. {@link RestClientBuilder#strict()}), 631 * bean context property setters (e.g. {@link RestClientBuilder#swaps(Object...)}), or generic property setters (e.g. {@link RestClientBuilder#set(String, Object)}) defined on this builder class. 632 * 633 * <p> 634 * If the <c>Accept</c> header is not set on the request, it will be set to the media type of this parser. 635 * 636 * @param parser The parser used to parse POJOs from the body of the HTTP response. 637 * @return This object (for method chaining). 638 */ 639 public RestRequest parser(Class<? extends Parser> parser) { 640 this.parser = client.getInstance(parser); 641 return this; 642 } 643 644 /** 645 * Allows you to override what status codes are considered error codes that would result in a {@link RestCallException}. 646 * 647 * <p> 648 * The default error code predicate is: <code>x -> x >= 400</code>. 649 * 650 * @param value The new predicate for calculating error codes. 651 * @return This object (for method chaining). 652 */ 653 public RestRequest errorCodes(Predicate<Integer> value) { 654 this.errorCodes = value; 655 return this; 656 } 657 658 /** 659 * Add one or more interceptors for this call only. 660 * 661 * @param interceptors The interceptors to add to this call. 662 * @return This object (for method chaining). 663 * @throws RestCallException If init method on interceptor threw an exception. 664 */ 665 public RestRequest interceptors(RestCallInterceptor...interceptors) throws RestCallException { 666 try { 667 for (RestCallInterceptor i : interceptors) { 668 this.interceptors.add(i); 669 i.onInit(this); 670 } 671 } catch (RuntimeException | RestCallException e) { 672 throw e; 673 } catch (Exception e) { 674 throw new RestCallException(null, e, "Interceptor threw an exception on init."); 675 } 676 677 return this; 678 } 679 680 /** 681 * Prevent {@link RestCallException RestCallExceptions} from being thrown when HTTP status 400+ is encountered. 682 * 683 * <p> 684 * This overrides the <l>ignoreErrors</l> property on the client. 685 * 686 * @return This object (for method chaining). 687 */ 688 public RestRequest ignoreErrors() { 689 this.ignoreErrors = true; 690 return this; 691 } 692 693 /** 694 * Sets <c>Debug: value</c> header on this request. 695 * 696 * @return This object (for method chaining). 697 * @throws RestCallException Invalid input. 698 */ 699 public RestRequest debug() throws RestCallException { 700 header("Debug", true); 701 return this; 702 } 703 704 /** 705 * Returns <jk>true</jk> if debug mode is currently enabled. 706 */ 707 @Override 708 public boolean isDebug() { 709 return getHeader("Debug", "false").equalsIgnoreCase("true"); 710 } 711 712 /** 713 * Specifies the target host for the request. 714 * 715 * @param target The target host for the request. 716 * Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default 717 * target or by inspecting the request. 718 * @return This object (for method chaining). 719 */ 720 public RestRequest target(HttpHost target) { 721 this.target = target; 722 return this; 723 } 724 725 /** 726 * Override the context to use for the execution. 727 * 728 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 729 * @return This object (for method chaining). 730 */ 731 public RestRequest context(HttpContext context) { 732 this.context = context; 733 return this; 734 } 735 736 //------------------------------------------------------------------------------------------------------------------ 737 // URI 738 //------------------------------------------------------------------------------------------------------------------ 739 740 /** 741 * Sets the URI for this request. 742 * 743 * <p> 744 * Can be any of the following types: 745 * <ul> 746 * <li>{@link URI} 747 * <li>{@link URL} 748 * <li>{@link URIBuilder} 749 * <li>Anything else converted to a string using {@link Object#toString()}. 750 * </ul> 751 * 752 * <p> 753 * Relative URI strings will be interpreted as relative to the root URI defined on the client. 754 * 755 * @param uri 756 * The URI of the remote REST resource. 757 * <br>This overrides the URI passed in from the client. 758 * <br>Can be any of the following types: 759 * <ul> 760 * <li>{@link URIBuilder} 761 * <li>{@link URI} 762 * <li>{@link URL} 763 * <li>{@link String} 764 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 765 * </ul> 766 * @return This object (for method chaining). 767 * @throws RestCallException Invalid URI syntax detected. 768 */ 769 public RestRequest uri(Object uri) throws RestCallException { 770 URI x = client.toURI(uri, null); 771 if (x.getScheme() != null) 772 uriBuilder.setScheme(x.getScheme()); 773 if (x.getHost() != null) 774 uriBuilder.setHost(x.getHost()); 775 if (x.getPort() != -1) 776 uriBuilder.setPort(x.getPort()); 777 if (x.getUserInfo() != null) 778 uriBuilder.setUserInfo(x.getUserInfo()); 779 if (x.getFragment() != null) 780 uriBuilder.setFragment(x.getFragment()); 781 if (x.getQuery() != null) 782 uriBuilder.setCustomQuery(x.getQuery()); 783 uriBuilder.setPath(x.getPath()); 784 return this; 785 } 786 787 /** 788 * Sets the URI scheme. 789 * 790 * @param scheme The new URI host. 791 * @return This object (for method chaining). 792 */ 793 public RestRequest scheme(String scheme) { 794 uriBuilder.setScheme(scheme); 795 return this; 796 } 797 798 /** 799 * Sets the URI host. 800 * 801 * @param host The new URI host. 802 * @return This object (for method chaining). 803 */ 804 public RestRequest host(String host) { 805 uriBuilder.setHost(host); 806 return this; 807 } 808 809 /** 810 * Sets the URI port. 811 * 812 * @param port The new URI port. 813 * @return This object (for method chaining). 814 */ 815 public RestRequest port(int port) { 816 uriBuilder.setPort(port); 817 return this; 818 } 819 820 /** 821 * Sets the URI user info. 822 * 823 * @param userInfo The new URI user info. 824 * @return This object (for method chaining). 825 */ 826 public RestRequest userInfo(String userInfo) { 827 uriBuilder.setUserInfo(userInfo); 828 return this; 829 } 830 831 /** 832 * Sets the URI user info. 833 * 834 * @param username The new URI username. 835 * @param password The new URI password. 836 * @return This object (for method chaining). 837 */ 838 public RestRequest userInfo(String username, String password) { 839 uriBuilder.setUserInfo(username, password); 840 return this; 841 } 842 843 /** 844 * Sets the URI fragment. 845 * 846 * @param fragment The URI fragment. The value is expected to be unescaped and may contain non ASCII characters. 847 * @return This object (for method chaining). 848 */ 849 public RestRequest fragment(String fragment) { 850 uriBuilder.setFragment(fragment); 851 return this; 852 } 853 854 //------------------------------------------------------------------------------------------------------------------ 855 // Path 856 //------------------------------------------------------------------------------------------------------------------ 857 858 /** 859 * Replaces a path parameter of the form <js>"{name}"</js> in the URI. 860 * 861 * <h5 class='section'>Example:</h5> 862 * <p class='bcode w800'> 863 * <jc>// Sets path to "/bar".</jc> 864 * <jv>client</jv> 865 * .get(<js>"/{foo}"</js>) 866 * .path(<js>"foo"</js>, <js>"bar"</js>) 867 * .run(); 868 * </p> 869 * 870 * @param name The parameter name. 871 * @param value The parameter value. 872 * <ul> 873 * <li>Value can be any POJO or POJO {@link Supplier}. 874 * <li>Value converted to a string using the configured part serializer. 875 * </ul> 876 * @return This object (for method chaining). 877 * @throws RestCallException Invalid input. 878 */ 879 public RestRequest path(String name, Object value) throws RestCallException { 880 return paths(serializedNameValuePair(name, value, PATH, partSerializer, null, null)); 881 } 882 883 /** 884 * Replaces a path parameter of the form <js>"{name}"</js> in the URI. 885 * 886 * <h5 class='section'>Example:</h5> 887 * <p class='bcode w800'> 888 * <jc>// Sets path to "/bar".</jc> 889 * <jv>client</jv> 890 * .get(<js>"/{foo}"</js>) 891 * .path(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) 892 * .run(); 893 * </p> 894 * 895 * @param pair The parameter. 896 * @return This object (for method chaining). 897 * @throws RestCallException Invalid input. 898 */ 899 public RestRequest path(NameValuePair pair) throws RestCallException { 900 return paths(pair); 901 } 902 903 /** 904 * Replaces a path parameter of the form <js>"{name}"</js> in the URI. 905 * 906 * <h5 class='section'>Example:</h5> 907 * <p class='bcode w800'> 908 * <jc>// Sets path to "/bar|baz".</jc> 909 * <jv>client</jv> 910 * .get(<js>"/{foo}"</js>) 911 * .path( 912 * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), 913 * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> 914 * ) 915 * .run(); 916 * </p> 917 * 918 * @param name The parameter name. 919 * @param value The parameter value. 920 * <ul> 921 * <li>Value can be any POJO or POJO {@link Supplier}. 922 * <li>Value converted to a string using the configured part serializer. 923 * </ul> 924 * @param schema The part schema. Can be <jk>null</jk>. 925 * @return This object (for method chaining). 926 * @throws RestCallException Invalid input. 927 */ 928 public RestRequest path(String name, Object value, HttpPartSchema schema) throws RestCallException { 929 return paths(serializedNameValuePair(name, value, PATH, partSerializer, schema, null)); 930 } 931 932 /** 933 * Replaces multiple path parameter of the form <js>"{name}"</js> in the URI. 934 * 935 * <h5 class='section'>Example:</h5> 936 * <p class='bcode w800'> 937 * <jc>// Sets path to "/baz/qux".</jc> 938 * <jv>client</jv> 939 * .get(<js>"/{foo}/{bar}"</js>) 940 * .paths( 941 * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"baz"</js>), 942 * AMap.<jsm>of</jsm>(<js>"bar"</js>, <js>"qux"</js>) 943 * ) 944 * .run(); 945 * </p> 946 * 947 * @param params 948 * The path parameters to set. 949 * <br>Can be any of the following types: 950 * <ul> 951 * <li>{@link NameValuePair} 952 * <li>{@link NameValuePairable} 953 * <li>{@link java.util.Map.Entry} 954 * <li>{@link NameValuePairSupplier} 955 * <li>{@link Map} 956 * <ul> 957 * <li>Values can be any POJO. 958 * <li>Values converted to a string using the configured part serializer. 959 * </ul> 960 * <li>A collection or array of anything on this list. 961 * </ul> 962 * @return This object (for method chaining). 963 * @throws RestCallException Invalid input. 964 */ 965 @SuppressWarnings("rawtypes") 966 public RestRequest paths(Object...params) throws RestCallException { 967 for (Object o : params) { 968 if (BasicNameValuePair.canCast(o)) { 969 innerPath(BasicNameValuePair.cast(o)); 970 } else if (o instanceof NameValuePairSupplier) { 971 for (NameValuePair p : (NameValuePairSupplier)o) 972 innerPath(p); 973 } else if (o instanceof Collection) { 974 for (Object o2 : (Collection<?>)o) 975 innerPath(BasicNameValuePair.cast(o2)); 976 } else if (o != null && o.getClass().isArray()) { 977 for (int i = 0; i < Array.getLength(o); i++) 978 innerPath(BasicNameValuePair.cast(Array.get(o, i))); 979 } else if (o instanceof Map) { 980 for (Map.Entry e : toMap(o).entrySet()) 981 innerPath(serializedNameValuePair(e.getKey(), e.getValue(), PATH, partSerializer, null, null)); 982 } else if (isBean(o)) { 983 for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) 984 innerPath(serializedNameValuePair(e.getKey(), e.getValue(), PATH, partSerializer, null, null)); 985 } else if (o != null) { 986 throw new RestCallException(null, null, "Invalid type passed to paths(): {0}", className(o)); 987 } 988 } 989 return this; 990 } 991 992 /** 993 * Replaces path parameters of the form <js>"{name}"</js> in the URI using free-form key/value pairs. 994 * 995 * <h5 class='section'>Example:</h5> 996 * <p class='bcode w800'> 997 * <jc>// Sets path to "/baz/qux".</jc> 998 * <jv>client</jv> 999 * .get(<js>"/{foo}/{bar}"</js>) 1000 * .pathPairs( 1001 * <js>"foo"</js>,<js>"baz"</js>, 1002 * <js>"bar"</js>,<js>"qux"</js> 1003 * ) 1004 * .run(); 1005 * </p> 1006 * 1007 * @param pairs The path key/value pairs. 1008 * <ul> 1009 * <li>Values can be any POJO. 1010 * <li>Values converted to a string using the configured part serializer. 1011 * </ul> 1012 * @return This object (for method chaining). 1013 * @throws RestCallException Invalid input. 1014 */ 1015 public RestRequest pathPairs(Object...pairs) throws RestCallException { 1016 if (pairs.length % 2 != 0) 1017 throw new RestCallException(null, null, "Odd number of parameters passed into pathPairs()"); 1018 for (int i = 0; i < pairs.length; i+=2) 1019 paths(serializedNameValuePair(pairs[i], pairs[i+1], PATH, partSerializer, null, null)); 1020 return this; 1021 } 1022 1023 RestRequest pathArg(String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { 1024 boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairSupplier || isNameValuePairArray(value); 1025 1026 if (! isMulti) 1027 return innerPath(serializedNameValuePair(name, value, PATH, serializer, schema, null)); 1028 1029 if (BasicNameValuePair.canCast(value)) { 1030 innerPath(BasicNameValuePair.cast(value)); 1031 } else if (value instanceof NameValuePairSupplier) { 1032 for (Object o : (NameValuePairSupplier)value) 1033 innerPath(BasicNameValuePair.cast(o)); 1034 } else if (value instanceof Collection) { 1035 for (Object o : (Collection<?>)value) 1036 innerPath(BasicNameValuePair.cast(o)); 1037 } else if (value != null && value.getClass().isArray()) { 1038 for (int i = 0; i < Array.getLength(value); i++) 1039 innerPath(BasicNameValuePair.cast(Array.get(value, i))); 1040 } else if (value instanceof Map) { 1041 for (Map.Entry<Object,Object> p : toMap(value).entrySet()) 1042 innerPath(serializedNameValuePair(p.getKey(), p.getValue(), PATH, serializer, schema, null)); 1043 } else if (isBean(value)) { 1044 for (Map.Entry<String,Object> p : toBeanMap(value).entrySet()) 1045 innerPath(serializedNameValuePair(p.getKey(), p.getValue(), PATH, serializer, schema, null)); 1046 } else if (value != null) { 1047 throw new RestCallException(null, null, "Invalid value type for path arg ''{0}'': {1}", name, className(value)); 1048 } 1049 return this; 1050 } 1051 1052 private RestRequest innerPath(NameValuePair param) throws RestCallException { 1053 String path = uriBuilder.getPath(); 1054 String name = param.getName(), value = param.getValue(); 1055 String var = "{" + name + "}"; 1056 if (path.indexOf(var) == -1 && ! name.equals("/*")) 1057 throw new RestCallException(null, null, "Path variable {"+name+"} was not found in path."); 1058 String p = null; 1059 if (name.equals("/*")) 1060 p = path.replaceAll("\\/\\*$", "/" + value); 1061 else 1062 p = path.replace(var, String.valueOf(value)); 1063 uriBuilder.setPath(p); 1064 return this; 1065 } 1066 1067 //------------------------------------------------------------------------------------------------------------------ 1068 // Query 1069 //------------------------------------------------------------------------------------------------------------------ 1070 1071 /** 1072 * Sets a query parameter on the URI. 1073 * 1074 * <h5 class='section'>Example:</h5> 1075 * <p class='bcode w800'> 1076 * <jc>// Adds query parameter "foo=bar|baz".</jc> 1077 * <jv>client</jv> 1078 * .get(<jsf>URI</jsf>) 1079 * .query( 1080 * <jsf>APPEND</jsf>, 1081 * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), 1082 * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> 1083 * ) 1084 * .run(); 1085 * </p> 1086 * 1087 * @param flag How to add this parameter. 1088 * <ul> 1089 * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. 1090 * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. 1091 * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. 1092 * </ul> 1093 * @param name The parameter name. 1094 * @param value The parameter value. 1095 * <ul> 1096 * <li>Value can be any POJO or POJO {@link Supplier}. 1097 * <li>Value converted to a string using the configured part serializer. 1098 * </ul> 1099 * @param schema The schema object that defines the format of the output. 1100 * <ul> 1101 * <li>If <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 1102 * <li>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 1103 * </ul> 1104 * @return This object (for method chaining). 1105 * @throws RestCallException Invalid input. 1106 */ 1107 public RestRequest query(AddFlag flag, String name, Object value, HttpPartSchema schema) throws RestCallException { 1108 return queries(flag, serializedNameValuePair(name, value, QUERY, partSerializer, schema, EnumSet.of(flag))); 1109 } 1110 1111 /** 1112 * Adds a query parameter to the URI. 1113 * 1114 * <h5 class='section'>Example:</h5> 1115 * <p class='bcode w800'> 1116 * <jc>// Adds query parameter "foo=bar".</jc> 1117 * <jv>client</jv> 1118 * .get(<jsf>URI</jsf>) 1119 * .query(<js>"foo"</js>, <js>"bar"</js>) 1120 * .run(); 1121 * </p> 1122 * 1123 * @param name The parameter name. 1124 * @param value The parameter value. 1125 * <ul> 1126 * <li>Value can be any POJO or POJO {@link Supplier}. 1127 * <li>Value converted to a string using the configured part serializer. 1128 * </ul> 1129 * @return This object (for method chaining). 1130 * @throws RestCallException Invalid input. 1131 */ 1132 public RestRequest query(String name, Object value) throws RestCallException { 1133 return queries(serializedNameValuePair(name, value, QUERY, partSerializer, null, null)); 1134 } 1135 1136 /** 1137 * Adds a query parameter to the URI. 1138 * 1139 * <h5 class='section'>Example:</h5> 1140 * <p class='bcode w800'> 1141 * <jc>// Adds query parameter "foo=bar".</jc> 1142 * <jv>client</jv> 1143 * .get(<jsf>URI</jsf>) 1144 * .query(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) 1145 * .run(); 1146 * </p> 1147 * 1148 * @param pair The parameter. 1149 * @return This object (for method chaining). 1150 * @throws RestCallException Invalid input. 1151 */ 1152 public RestRequest query(NameValuePair pair) throws RestCallException { 1153 return queries(pair); 1154 } 1155 1156 /** 1157 * Adds a query parameter to the URI. 1158 * 1159 * <p> 1160 * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). 1161 * 1162 * <h5 class='section'>Example:</h5> 1163 * <p class='bcode w800'> 1164 * <jc>// Creates query parameter "foo=bar|baz"</jc> 1165 * <jv>client</jv> 1166 * .get(<jsf>URI</jsf>) 1167 * .query( 1168 * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), 1169 * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> 1170 * ) 1171 * .run(); 1172 * </p> 1173 * 1174 * @param name The parameter name. 1175 * @param value The parameter value. 1176 * <ul> 1177 * <li>Value can be any POJO or POJO {@link Supplier}. 1178 * <li>Value converted to a string using the configured part serializer. 1179 * </ul> 1180 * @param schema The HTTP part schema. Can be <jk>null</jk>. 1181 * @return This object (for method chaining). 1182 * @throws RestCallException Invalid input. 1183 */ 1184 public RestRequest query(String name, Object value, HttpPartSchema schema) throws RestCallException { 1185 return queries(serializedNameValuePair(name, value, QUERY, partSerializer, schema, null)); 1186 } 1187 1188 /** 1189 * Adds a query parameter to the URI. 1190 * 1191 * <h5 class='section'>Example:</h5> 1192 * <p class='bcode w800'> 1193 * <jc>// Adds query parameter "foo=bar".</jc> 1194 * <jv>client</jv> 1195 * .get(<jsf>URI</jsf>) 1196 * .query( 1197 * <jsf>APPEND</jsf>, 1198 * <js>"foo"</js>, <js>"bar"</js> 1199 * ) 1200 * .run(); 1201 * </p> 1202 * 1203 * @param flag How to add this parameter. 1204 * <ul> 1205 * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. 1206 * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. 1207 * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. 1208 * </ul> 1209 * @param name The parameter name. 1210 * @param value The parameter value. 1211 * <ul> 1212 * <li>Value can be any POJO or POJO {@link Supplier}. 1213 * <li>Value converted to a string using the configured part serializer. 1214 * </ul> 1215 * @return This object (for method chaining). 1216 * @throws RestCallException Invalid input. 1217 */ 1218 public RestRequest query(AddFlag flag, String name, Object value) throws RestCallException { 1219 return queries(flag, serializedNameValuePair(name, value, QUERY, partSerializer, null, EnumSet.of(flag))); 1220 } 1221 1222 /** 1223 * Sets multiple parameters on the query string. 1224 * 1225 * <h5 class='section'>Example:</h5> 1226 * <p class='bcode w800'> 1227 * <jc>// Adds query parameters "foo=bar&baz=qux".</jc> 1228 * <jv>client</jv> 1229 * .get(<jsf>URI</jsf>) 1230 * .queries( 1231 * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>), 1232 * AMap.<jsm>of</jsm>(<js>"baz"</js>,<js>"qux"</js>) 1233 * ) 1234 * .run(); 1235 * </p> 1236 * 1237 * @param params 1238 * The parameters to set. 1239 * <br>Can be any of the following types: 1240 * <ul> 1241 * <li>{@link NameValuePair} 1242 * <li>{@link NameValuePairable} 1243 * <li>{@link java.util.Map.Entry} 1244 * <li>{@link NameValuePairSupplier} 1245 * <li>{@link Map} 1246 * <ul> 1247 * <li>Values can be any POJO. 1248 * <li>Values converted to a string using the configured part serializer. 1249 * </ul> 1250 * <li>A collection or array of anything on this list. 1251 * </ul> 1252 * @return This object (for method chaining). 1253 * @throws RestCallException Invalid input. 1254 */ 1255 public RestRequest queries(Object...params) throws RestCallException { 1256 return queries(APPEND, params); 1257 } 1258 1259 /** 1260 * Sets multiple parameters on the query string. 1261 * 1262 * <h5 class='section'>Example:</h5> 1263 * <p class='bcode w800'> 1264 * <jc>// Adds query parameters "foo=bar&baz=qux".</jc> 1265 * <jv>client</jv> 1266 * .get(<jsf>URI</jsf>) 1267 * .queries( 1268 * <jsf>APPEND</jsf>, 1269 * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>), 1270 * AMap.<jsm>of</jsm>(<js>"baz"</js>,<js>"qux"</js>) 1271 * ) 1272 * .run(); 1273 * </p> 1274 * 1275 * @param flag How to add this parameter. 1276 * <ul> 1277 * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. 1278 * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. 1279 * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. 1280 * </ul> 1281 * @param params 1282 * The parameters to set. 1283 * <br>Can be any of the following types: 1284 * <ul> 1285 * <li>{@link NameValuePair} 1286 * <li>{@link NameValuePairable} 1287 * <li>{@link java.util.Map.Entry} 1288 * <li>{@link NameValuePairSupplier} 1289 * <li>{@link Map} 1290 * <ul> 1291 * <li>Values can be any POJO. 1292 * <li>Values converted to a string using the configured part serializer. 1293 * </ul> 1294 * <li>A collection or array of anything on this list. 1295 * </ul> 1296 * @return This object (for method chaining). 1297 * @throws RestCallException Invalid input. 1298 */ 1299 public RestRequest queries(AddFlag flag, Object...params) throws RestCallException { 1300 List<NameValuePair> l = new ArrayList<>(); 1301 for (Object o : params) { 1302 if (BasicNameValuePair.canCast(o)) { 1303 l.add(BasicNameValuePair.cast(o)); 1304 } else if (o instanceof NameValuePairSupplier) { 1305 for (NameValuePair p : (NameValuePairSupplier)o) 1306 l.add(p); 1307 } else if (o instanceof Collection) { 1308 for (Object o2 : (Collection<?>)o) 1309 l.add(BasicNameValuePair.cast(o2)); 1310 } else if (o != null && o.getClass().isArray()) { 1311 for (int i = 0; i < Array.getLength(o); i++) 1312 l.add(BasicNameValuePair.cast(Array.get(o, i))); 1313 } else if (o instanceof Map) { 1314 for (Map.Entry<Object,Object> e : toMap(o).entrySet()) 1315 l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, partSerializer, null, EnumSet.of(flag))); 1316 } else if (isBean(o)) { 1317 for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) 1318 l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, partSerializer, null, EnumSet.of(flag))); 1319 } else if (o != null) { 1320 throw new RestCallException(null, null, "Invalid type passed to queries(): {0}", className(o)); 1321 } 1322 } 1323 return innerQuery(EnumSet.of(flag), l); 1324 } 1325 1326 /** 1327 * Adds query parameters to the URI query using free-form key/value pairs.. 1328 * 1329 * <h5 class='section'>Example:</h5> 1330 * <p class='bcode w800'> 1331 * <jc>// Adds query parameters "foo=bar&baz=qux".</jc> 1332 * <jv>client</jv> 1333 * .get(<jsf>URI</jsf>) 1334 * .queryPairs(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>) 1335 * .run(); 1336 * </p> 1337 * 1338 * @param pairs The query key/value pairs. 1339 * <ul> 1340 * <li>Values can be any POJO. 1341 * <li>Values converted to a string using the configured part serializer. 1342 * </ul> 1343 * @return This object (for method chaining). 1344 * @throws RestCallException Invalid input. 1345 */ 1346 public RestRequest queryPairs(Object...pairs) throws RestCallException { 1347 if (pairs.length % 2 != 0) 1348 throw new RestCallException(null, null, "Odd number of parameters passed into queryPairs()"); 1349 for (int i = 0; i < pairs.length; i+=2) 1350 queries(serializedNameValuePair(pairs[i], pairs[i+1], QUERY, partSerializer, null, null)); 1351 return this; 1352 } 1353 1354 /** 1355 * Adds a free-form custom query. 1356 * 1357 * <h5 class='section'>Example:</h5> 1358 * <p class='bcode w800'> 1359 * <jc>// Adds query parameter "foo=bar&baz=qux".</jc> 1360 * <jv>client</jv> 1361 * .get(<jsf>URI</jsf>) 1362 * .queryCustom(<js>"foo=bar&baz=qux"</js>) 1363 * .run(); 1364 * </p> 1365 * 1366 * @param value The parameter value. 1367 * <br>Can be any of the following types: 1368 * <ul> 1369 * <li> 1370 * {@link CharSequence} 1371 * <li> 1372 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 1373 * <li> 1374 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 1375 * <li> 1376 * {@link NameValuePairSupplier} - Converted to a URL-encoded query. 1377 * </ul> 1378 * @return This object (for method chaining). 1379 * @throws RestCallException Invalid input. 1380 */ 1381 public RestRequest queryCustom(Object value) throws RestCallException { 1382 try { 1383 String q = null; 1384 if (value instanceof Reader) 1385 q = IOUtils.read((Reader)value); 1386 else if (value instanceof InputStream) 1387 q = IOUtils.read((InputStream)value); 1388 else 1389 q = stringify(value); // Works for NameValuePairs. 1390 uriBuilder.setCustomQuery(q); 1391 } catch (IOException e) { 1392 throw new RestCallException(null, e, "Could not read custom query."); 1393 } 1394 return this; 1395 } 1396 1397 RestRequest queryArg(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { 1398 flags = AddFlag.orDefault(flags); 1399 boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairSupplier || isNameValuePairArray(value); 1400 1401 if (! isMulti) 1402 return innerQuery(flags, AList.of(serializedNameValuePair(name, value, QUERY, serializer, schema, flags))); 1403 1404 List<NameValuePair> l = AList.of(); 1405 1406 if (BasicNameValuePair.canCast(value)) { 1407 l.add(BasicNameValuePair.cast(value)); 1408 } else if (value instanceof NameValuePairSupplier) { 1409 for (Object o : (NameValuePairSupplier)value) 1410 l.add(BasicNameValuePair.cast(o)); 1411 } else if (value instanceof Collection) { 1412 for (Object o : (Collection<?>)value) 1413 l.add(BasicNameValuePair.cast(o)); 1414 } else if (value != null && value.getClass().isArray()) { 1415 for (int i = 0; i < Array.getLength(value); i++) 1416 l.add(BasicNameValuePair.cast(Array.get(value, i))); 1417 } else if (value instanceof Map) { 1418 for (Map.Entry<Object,Object> e : toMap(value).entrySet()) 1419 l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, serializer, schema, flags)); 1420 } else if (isBean(value)) { 1421 for (Map.Entry<String,Object> e : toBeanMap(value).entrySet()) 1422 l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, serializer, schema, flags)); 1423 } else { 1424 return queryCustom(value); 1425 } 1426 1427 return innerQuery(flags, l); 1428 } 1429 1430 private RestRequest innerQuery(EnumSet<AddFlag> flags, List<NameValuePair> params) { 1431 flags = AddFlag.orDefault(flags); 1432 params.removeIf(x -> x.getValue() == null); 1433 if (flags.contains(SKIP_IF_EMPTY)) 1434 params.removeIf(x -> isEmpty(x.getValue())); 1435 if (flags.contains(REPLACE)) { 1436 List<NameValuePair> l = uriBuilder.getQueryParams(); 1437 for (NameValuePair p : params) 1438 for (Iterator<NameValuePair> i = l.iterator(); i.hasNext();) 1439 if (i.next().getName().equals(p.getName())) 1440 i.remove(); 1441 l.addAll(params); 1442 uriBuilder.setParameters(l); 1443 } else if (flags.contains(PREPEND)) { 1444 List<NameValuePair> l = uriBuilder.getQueryParams(); 1445 l.addAll(0, params); 1446 uriBuilder.setParameters(l); 1447 } else { 1448 uriBuilder.addParameters(params); 1449 } 1450 return this; 1451 } 1452 1453 //------------------------------------------------------------------------------------------------------------------ 1454 // Form data 1455 //------------------------------------------------------------------------------------------------------------------ 1456 1457 /** 1458 * Adds a form-data parameter to the request body. 1459 * 1460 * <h5 class='section'>Example:</h5> 1461 * <p class='bcode w800'> 1462 * <jc>// Adds form data parameter "foo=bar|baz".</jc> 1463 * <jv>client</jv> 1464 * .formPost(<jsf>URI</jsf>) 1465 * .formData( 1466 * <jsf>APPEND</jsf>, 1467 * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), 1468 * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> 1469 * .run(); 1470 * </p> 1471 * 1472 * @param flag How to add this parameter. 1473 * <ul> 1474 * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. 1475 * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. 1476 * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. 1477 * </ul> 1478 * @param name The parameter name. 1479 * @param value The parameter value. 1480 * <ul> 1481 * <li>Value can be any POJO or POJO {@link Supplier}. 1482 * <li>Value converted to a string using the configured part serializer. 1483 * </ul> 1484 * @param schema The schema object that defines the format of the output. 1485 * <ul> 1486 * <li>If <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 1487 * <li>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 1488 * </ul> 1489 * @return This object (for method chaining). 1490 * @throws RestCallException Invalid input. 1491 */ 1492 public RestRequest formData(AddFlag flag, String name, Object value, HttpPartSchema schema) throws RestCallException { 1493 return formDatas(flag, serializedNameValuePair(name, value, FORMDATA, partSerializer, schema, EnumSet.of(flag))); 1494 } 1495 1496 /** 1497 * Adds a form-data parameter to the request body. 1498 * 1499 * <h5 class='section'>Example:</h5> 1500 * <p class='bcode w800'> 1501 * <jc>// Adds form data parameter "foo=bar|baz".</jc> 1502 * <jv>client</jv> 1503 * .formPost(<jsf>URI</jsf>) 1504 * .formData(<js>"foo"</js>, <js>"bar"</js>) 1505 * .run(); 1506 * </p> 1507 * 1508 * @param name The parameter name. 1509 * @param value The parameter value. 1510 * <ul> 1511 * <li>Value can be any POJO or POJO {@link Supplier}. 1512 * <li>Value converted to a string using the configured part serializer. 1513 * </ul> 1514 * @return This object (for method chaining). 1515 * @throws RestCallException Invalid input. 1516 */ 1517 public RestRequest formData(String name, Object value) throws RestCallException { 1518 return formDatas(serializedNameValuePair(name, value, FORMDATA, partSerializer, null, null)); 1519 } 1520 1521 /** 1522 * Adds a form-data parameter to the request body. 1523 * 1524 * <h5 class='section'>Example:</h5> 1525 * <p class='bcode w800'> 1526 * <jc>// Adds form data parameter "foo=bar".</jc> 1527 * <jv>client</jv> 1528 * .formPost(<jsf>URI</jsf>) 1529 * .formData(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) 1530 * .run(); 1531 * </p> 1532 * 1533 * @param pair The parameter. 1534 * @return This object (for method chaining). 1535 * @throws RestCallException Invalid input. 1536 */ 1537 public RestRequest formData(NameValuePair pair) throws RestCallException { 1538 return formDatas(pair); 1539 } 1540 1541 /** 1542 * Adds a form-data parameter to the request body. 1543 * 1544 * <p> 1545 * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). 1546 * 1547 * <h5 class='section'>Example:</h5> 1548 * <p class='bcode w800'> 1549 * <jc>// Adds form data parameter "foo=bar|baz".</jc> 1550 * <jv>client</jv> 1551 * .formPost(<jsf>URI</jsf>) 1552 * .formData( 1553 * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), 1554 * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> 1555 * ) 1556 * .run(); 1557 * </p> 1558 * 1559 * @param name The parameter name. 1560 * @param value The parameter value. 1561 * <ul> 1562 * <li>Value can be any POJO or POJO {@link Supplier}. 1563 * <li>Value converted to a string using the configured part serializer. 1564 * </ul> 1565 * @param schema The HTTP part schema. Can be <jk>null</jk>. 1566 * @return This object (for method chaining). 1567 * @throws RestCallException Invalid input. 1568 */ 1569 public RestRequest formData(String name, Object value, HttpPartSchema schema) throws RestCallException { 1570 return formDatas(serializedNameValuePair(name, value, FORMDATA, partSerializer, schema, null)); 1571 } 1572 1573 /** 1574 * Adds a form-data parameter to the request body. 1575 * 1576 * <h5 class='section'>Example:</h5> 1577 * <p class='bcode w800'> 1578 * <jc>// Adds form data parameter "foo=bar".</jc> 1579 * <jv>client</jv> 1580 * .formPost(<jsf>URI</jsf>) 1581 * .formData( 1582 * <jsf>APPEND</jsf>, 1583 * <js>"foo"</js>, <js>"bar"</js> 1584 * ) 1585 * .run(); 1586 * </p> 1587 * 1588 * @param flag How to add this parameter. 1589 * <ul> 1590 * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. 1591 * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. 1592 * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. 1593 * </ul> 1594 * @param name The parameter name. 1595 * @param value The parameter value. 1596 * <ul> 1597 * <li>Value can be any POJO or POJO {@link Supplier}. 1598 * <li>Value converted to a string using the configured part serializer. 1599 * </ul> 1600 * @return This object (for method chaining). 1601 * @throws RestCallException Invalid input. 1602 */ 1603 public RestRequest formData(AddFlag flag, String name, Object value) throws RestCallException { 1604 return formDatas(flag, serializedNameValuePair(name, value, FORMDATA, partSerializer, null, EnumSet.of(flag))); 1605 } 1606 1607 /** 1608 * Adds a form-data parameter to the request body. 1609 * 1610 * <h5 class='section'>Example:</h5> 1611 * <p class='bcode w800'> 1612 * <jc>// Adds form data parameters "foo=bar&baz=qux".</jc> 1613 * <jv>client</jv> 1614 * .formPost(<jsf>URI</jsf>) 1615 * .formDatas( 1616 * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>), 1617 * AMap.<jsm>of</jsm>(<js>"baz"</js>,<js>"qux"</js>) 1618 * ) 1619 * .run(); 1620 * </p> 1621 * 1622 * @param params 1623 * The parameters to set. 1624 * <br>Can be any of the following types: 1625 * <ul> 1626 * <li>{@link NameValuePair} 1627 * <li>{@link NameValuePairable} 1628 * <li>{@link java.util.Map.Entry} 1629 * <li>{@link NameValuePairSupplier} 1630 * <li>{@link Map} 1631 * <ul> 1632 * <li>Values can be any POJO. 1633 * <li>Values converted to a string using the configured part serializer. 1634 * </ul> 1635 * <li>A collection or array of anything on this list. 1636 * </ul> 1637 * @return This object (for method chaining). 1638 * @throws RestCallException Invalid input. 1639 */ 1640 public RestRequest formDatas(Object...params) throws RestCallException { 1641 return formDatas(APPEND, params); 1642 } 1643 1644 /** 1645 * Adds multiple form-data parameters to the request body. 1646 * 1647 * <h5 class='section'>Example:</h5> 1648 * <p class='bcode w800'> 1649 * <jc>// Adds form data parameters "foo=bar&baz=qux".</jc> 1650 * <jv>client</jv> 1651 * .formPost(<jsf>URI</jsf>) 1652 * .formDatas( 1653 * <jsf>APPEND</jsf>, 1654 * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>), 1655 * AMap.<jsm>of</jsm>(<js>"baz"</js>,<js>"qux"</js>) 1656 * ) 1657 * .run(); 1658 * </p> 1659 * 1660 * @param flag How to add this parameter. 1661 * <ul> 1662 * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. 1663 * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. 1664 * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. 1665 * </ul> 1666 * @param params 1667 * The parameters to set. 1668 * <br>Can be any of the following types: 1669 * <ul> 1670 * <li>{@link NameValuePair} 1671 * <li>{@link NameValuePairable} 1672 * <li>{@link java.util.Map.Entry} 1673 * <li>{@link NameValuePairSupplier} 1674 * <li>{@link Map} 1675 * <ul> 1676 * <li>Values can be any POJO. 1677 * <li>Values converted to a string using the configured part serializer. 1678 * </ul> 1679 * <li>A collection or array of anything on this list. 1680 * </ul> 1681 * @return This object (for method chaining). 1682 * @throws RestCallException Invalid input. 1683 */ 1684 public RestRequest formDatas(AddFlag flag, Object...params) throws RestCallException { 1685 List<NameValuePair> l = new ArrayList<>(); 1686 for (Object o : params) { 1687 if (BasicNameValuePair.canCast(o)) { 1688 l.add(BasicNameValuePair.cast(o)); 1689 } else if (o instanceof NameValuePairSupplier) { 1690 for (NameValuePair p : (NameValuePairSupplier)o) 1691 l.add(p); 1692 } else if (o instanceof Collection) { 1693 for (Object o2 : (Collection<?>)o) 1694 l.add(BasicNameValuePair.cast(o2)); 1695 } else if (o != null && o.getClass().isArray()) { 1696 for (int i = 0; i < Array.getLength(o); i++) 1697 l.add(BasicNameValuePair.cast(Array.get(o, i))); 1698 } else if (o instanceof Map) { 1699 for (Map.Entry<Object,Object> e : toMap(o).entrySet()) 1700 l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, partSerializer, null, EnumSet.of(flag))); 1701 } else if (isBean(o)) { 1702 for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) 1703 l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, partSerializer, null, EnumSet.of(flag))); 1704 } else if (o != null) { 1705 throw new RestCallException(null, null, "Invalid type passed to formDatas(): {0}", className(o)); 1706 } 1707 } 1708 return innerFormData(EnumSet.of(flag), l); 1709 } 1710 1711 /** 1712 * Adds form-data parameters to the request body using free-form key/value pairs. 1713 * 1714 * <h5 class='section'>Example:</h5> 1715 * <p class='bcode w800'> 1716 * <jc>// Creates form data "key1=val1&key2=val2".</jc> 1717 * <jv>client</jv> 1718 * .formPost(<jsf>URI</jsf>) 1719 * .formDataPairs(<js>"key1"</js>,<js>"val1"</js>,<js>"key2"</js>,<js>"val2"</js>) 1720 * .run(); 1721 * </p> 1722 * 1723 * @param pairs The form-data key/value pairs. 1724 * <ul> 1725 * <li>Values can be any POJO. 1726 * <li>Values converted to a string using the configured part serializer. 1727 * </ul> 1728 * @return This object (for method chaining). 1729 * @throws RestCallException Invalid input. 1730 */ 1731 public RestRequest formDataPairs(Object...pairs) throws RestCallException { 1732 if (pairs.length % 2 != 0) 1733 throw new RestCallException(null, null, "Odd number of parameters passed into formDataPairs()"); 1734 for (int i = 0; i < pairs.length; i+=2) 1735 formDatas(serializedNameValuePair(pairs[i], pairs[i+1], FORMDATA, partSerializer, null, null)); 1736 return this; 1737 } 1738 1739 /** 1740 * Adds form-data parameters as the entire body of the request. 1741 * 1742 * <h5 class='section'>Example:</h5> 1743 * <p class='bcode w800'> 1744 * <jc>// Creates form data "foo=bar&baz=qux".</jc> 1745 * <jv>client</jv> 1746 * .formPost(<jsf>URI</jsf>) 1747 * .formDataCustom(<js>"foo=bar&baz=qux"</js>) 1748 * .run(); 1749 * 1750 * <jc>// Creates form data "foo=bar&baz=qux" using StringEntity.</jc> 1751 * <jv>client</jv> 1752 * .formPost(<jsf>URI</jsf>) 1753 * .formDataCustom(<jk>new</jk> StringEntity(<js>"foo=bar&baz=qux"</js>,<js>"application/x-www-form-urlencoded"</js>)) 1754 * .run(); 1755 * 1756 * <jc>// Creates form data "foo=bar&baz=qux" using StringEntity and body().</jc> 1757 * <jv>client</jv> 1758 * .formPost(<jsf>URI</jsf>) 1759 * .body(<jk>new</jk> StringEntity(<js>"foo=bar&baz=qux"</js>,<js>"application/x-www-form-urlencoded"</js>)) 1760 * .run(); 1761 * </p> 1762 * 1763 * @param value The parameter value. 1764 * <br>Can be any of the following types: 1765 * <ul class='spaced-list'> 1766 * <li> 1767 * {@link CharSequence} 1768 * <li> 1769 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 1770 * <li> 1771 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 1772 * <li> 1773 * {@link HttpResource}/{@link BasicHttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 1774 * <li> 1775 * {@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 1776 * <li> 1777 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 1778 * {@link RestClient}. 1779 * <li> 1780 * {@link NameValuePairSupplier} - Converted to a URL-encoded FORM post. 1781 * </ul> 1782 * @return This object (for method chaining). 1783 * @throws RestCallException Invalid input. 1784 */ 1785 public RestRequest formDataCustom(Object value) throws RestCallException { 1786 contentType("application/x-www-form-urlencoded"); 1787 body(value instanceof CharSequence ? new StringReader(value.toString()) : value); 1788 return this; 1789 } 1790 1791 RestRequest formDataArg(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { 1792 flags = AddFlag.orDefault(flags); 1793 boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairSupplier || isNameValuePairArray(value); 1794 1795 if (! isMulti) 1796 return innerFormData(flags, AList.of(serializedNameValuePair(name, value, FORMDATA, serializer, schema, flags))); 1797 1798 List<NameValuePair> l = AList.of(); 1799 1800 if (BasicNameValuePair.canCast(value)) { 1801 l.add(BasicNameValuePair.cast(value)); 1802 } else if (value instanceof NameValuePairSupplier) { 1803 for (Object o : (NameValuePairSupplier)value) 1804 l.add(BasicNameValuePair.cast(o)); 1805 } else if (value instanceof Collection) { 1806 for (Object o : (Collection<?>)value) 1807 l.add(BasicNameValuePair.cast(o)); 1808 } else if (value != null && value.getClass().isArray()) { 1809 for (int i = 0; i < Array.getLength(value); i++) 1810 l.add(BasicNameValuePair.cast(Array.get(value, i))); 1811 } else if (value instanceof Map) { 1812 for (Map.Entry<Object,Object> e : toMap(value).entrySet()) 1813 l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, serializer, schema, flags)); 1814 } else if (isBean(value)) { 1815 for (Map.Entry<String,Object> e : toBeanMap(value).entrySet()) 1816 l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, serializer, schema, flags)); 1817 } else { 1818 return formDataCustom(value); 1819 } 1820 1821 return innerFormData(flags, l); 1822 } 1823 1824 private RestRequest innerFormData(EnumSet<AddFlag> flags, List<NameValuePair> params) { 1825 input = null; 1826 flags = AddFlag.orDefault(flags); 1827 params.removeIf(x -> x.getValue() == null); 1828 if (flags.contains(SKIP_IF_EMPTY)) 1829 params.removeIf(x -> isEmpty(x.getValue())); 1830 if (formData == null) 1831 formData = new ArrayList<>(); 1832 if (flags.contains(REPLACE)) { 1833 for (NameValuePair p : params) 1834 for (Iterator<NameValuePair> i = formData.iterator(); i.hasNext();) 1835 if (i.next().getName().equals(p.getName())) 1836 i.remove(); 1837 formData.addAll(params); 1838 } else if (flags.contains(PREPEND)) { 1839 formData.addAll(0, params); 1840 } else { 1841 formData.addAll(params); 1842 } 1843 return this; 1844 } 1845 1846 1847 //------------------------------------------------------------------------------------------------------------------ 1848 // Request body 1849 //------------------------------------------------------------------------------------------------------------------ 1850 1851 /** 1852 * Sets the body of this request. 1853 * 1854 * @param input 1855 * The input to be sent to the REST resource (only valid for PUT/POST/PATCH) requests. 1856 * <br>Can be of the following types: 1857 * <ul class='spaced-list'> 1858 * <li> 1859 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 1860 * <li> 1861 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 1862 * <li> 1863 * {@link HttpResource}/{@link BasicHttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 1864 * <li> 1865 * {@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 1866 * <li> 1867 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 1868 * {@link RestClient}. 1869 * <li> 1870 * {@link NameValuePairSupplier} - Converted to a URL-encoded FORM post. 1871 * <li> 1872 * A {@link Supplier} of anything on this list. 1873 * </ul> 1874 * @return This object (for method chaining). 1875 * @throws RestCallException If a retry was attempted, but the entity was not repeatable. 1876 */ 1877 public RestRequest body(Object input) throws RestCallException { 1878 this.input = input; 1879 this.hasInput = true; 1880 this.formData = null; 1881 return this; 1882 } 1883 1884 /** 1885 * Sets the body of this request as straight text bypassing the serializer. 1886 * 1887 * <p class='bcode w800'> 1888 * <jv>client</jv> 1889 * .put(<js>"/foo"</js>) 1890 * .body(<jk>new</jk> StringReader(<js>"foo"</js>)) 1891 * .contentType("" 1892 * .run(); 1893 * 1894 * <jv>client</jv> 1895 * .put(<js>"/foo"</js>) 1896 * .bodyString(<js>"foo"</js>) 1897 * .run(); 1898 * </p> 1899 * 1900 * <p> 1901 * Note that this is different than the following which will serialize <l>foo</l> as a JSON string <l>"foo"</l>. 1902 * <p class='bcode w800'> 1903 * <jv>client</jv> 1904 * .put(<js>"/foo"</js>) 1905 * .json() 1906 * .body(<js>"foo"</js>) 1907 * .run(); 1908 * </p> 1909 * 1910 * @param input 1911 * The input to be sent to the REST resource (only valid for PUT/POST/PATCH) requests. 1912 * @return This object (for method chaining). 1913 * @throws RestCallException If a retry was attempted, but the entity was not repeatable. 1914 */ 1915 public RestRequest bodyString(Object input) throws RestCallException { 1916 return body(input == null ? null : new StringReader(stringify(input))); 1917 } 1918 1919 /** 1920 * Sets the body of this request. 1921 * 1922 * @param input 1923 * The input to be sent to the REST resource (only valid for PUT/POST/PATCH) requests. 1924 * <br>Can be of the following types: 1925 * <ul class='spaced-list'> 1926 * <li> 1927 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 1928 * <li> 1929 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 1930 * <li> 1931 * {@link HttpResource}/{@link BasicHttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 1932 * <li> 1933 * {@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 1934 * <li> 1935 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 1936 * {@link RestClient}. 1937 * <li> 1938 * {@link NameValuePairSupplier} - Converted to a URL-encoded FORM post. 1939 * <li> 1940 * A {@link Supplier} of anything on this list. 1941 * </ul> 1942 * @param schema The schema object that defines the format of the output. 1943 * <ul> 1944 * <li>If <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 1945 * <li>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 1946 * </ul> 1947 * @return This object (for method chaining). 1948 * @throws RestCallException If a retry was attempted, but the entity was not repeatable. 1949 */ 1950 public RestRequest body(Object input, HttpPartSchema schema) throws RestCallException { 1951 this.input = input; 1952 this.hasInput = true; 1953 this.formData = null; 1954 this.requestBodySchema = schema; 1955 return this; 1956 } 1957 1958 //----------------------------------------------------------------------------------------------------------------- 1959 // Headers 1960 //----------------------------------------------------------------------------------------------------------------- 1961 1962 /** 1963 * Adds a header on the request. 1964 * 1965 * <h5 class='section'>Example:</h5> 1966 * <p class='bcode w800'> 1967 * <jc>// Adds header "Foo: bar|baz".</jc> 1968 * <jv>client</jv> 1969 * .get(<jsf>URI</jsf>) 1970 * .header( 1971 * <jsf>APPEND</jsf>, 1972 * <js>"Foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>)), 1973 * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> 1974 * ) 1975 * .run(); 1976 * </p> 1977 * 1978 * @param flag How to add this parameter. 1979 * <ul> 1980 * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. 1981 * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. 1982 * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. 1983 * </ul> 1984 * @param name The header name. 1985 * @param value The header value. 1986 * <ul> 1987 * <li>Value can be any POJO or POJO {@link Supplier}. 1988 * <li>Value converted to a string using the configured part serializer. 1989 * </ul> 1990 * @param schema The schema object that defines the format of the output. 1991 * <ul> 1992 * <li>If <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 1993 * <li>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 1994 * </ul> 1995 * @return This object (for method chaining). 1996 * @throws RestCallException Invalid input. 1997 */ 1998 public RestRequest header(AddFlag flag, String name, Object value, HttpPartSchema schema) throws RestCallException { 1999 return headers(flag, serializedHeader(name, value, partSerializer, schema, EnumSet.of(flag))); 2000 } 2001 2002 /** 2003 * Appends a header on the request. 2004 * 2005 * <h5 class='section'>Example:</h5> 2006 * <p class='bcode w800'> 2007 * <jc>// Adds header "Foo: bar".</jc> 2008 * <jv>client</jv> 2009 * .get(<jsf>URI</jsf>) 2010 * .header(<js>"Foo"</js>, <js>"bar"</js>) 2011 * .run(); 2012 * </p> 2013 * 2014 * @param name The header name. 2015 * @param value The header value. 2016 * <ul> 2017 * <li>Value can be any POJO or POJO {@link Supplier}. 2018 * <li>Value converted to a string using the configured part serializer. 2019 * </ul> 2020 * @return This object (for method chaining). 2021 * @throws RestCallException Invalid input. 2022 */ 2023 public RestRequest header(String name, Object value) throws RestCallException { 2024 return headers(serializedHeader(name, value, partSerializer, null, null)); 2025 } 2026 2027 /** 2028 * Appends a header on the request. 2029 * 2030 * <p> 2031 * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). 2032 * 2033 * <h5 class='section'>Example:</h5> 2034 * <p class='bcode w800'> 2035 * <jc>// Adds header "Foo: bar|baz".</jc> 2036 * <jv>client</jv> 2037 * .get(<jsf>URI</jsf>) 2038 * .header( 2039 * <js>"Foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), 2040 * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> 2041 * ) 2042 * .run(); 2043 * </p> 2044 * 2045 * @param name The header name. 2046 * @param value The header value. 2047 * <ul> 2048 * <li>Value can be any POJO or POJO {@link Supplier}. 2049 * <li>Value converted to a string using the configured part serializer. 2050 * </ul> 2051 * @param schema The HTTP part schema. Can be <jk>null</jk>. 2052 * @return This object (for method chaining). 2053 * @throws RestCallException Invalid input. 2054 */ 2055 public RestRequest header(String name, Object value, HttpPartSchema schema) throws RestCallException { 2056 return headers(serializedHeader(name, value, partSerializer, schema, null)); 2057 } 2058 2059 /** 2060 * Adds a header to the request. 2061 * 2062 * <h5 class='section'>Example:</h5> 2063 * <p class='bcode w800'> 2064 * <jc>// Adds header "Foo: bar".</jc> 2065 * <jv>client</jv> 2066 * .get(<jsf>URI</jsf>) 2067 * .header( 2068 * <jsf>APPEND</jsf>, 2069 * <js>"Foo"</js>, <js>"bar"</js> 2070 * ) 2071 * .run(); 2072 * </p> 2073 * 2074 * @param flag How to add this parameter. 2075 * <ul> 2076 * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. 2077 * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. 2078 * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. 2079 * </ul> 2080 * @param name The header name. 2081 * @param value The header value. 2082 * <ul> 2083 * <li>Value can be any POJO or POJO {@link Supplier}. 2084 * <li>Value converted to a string using the configured part serializer. 2085 * </ul> 2086 * @return This object (for method chaining). 2087 * @throws RestCallException Invalid input. 2088 */ 2089 public RestRequest header(AddFlag flag, String name, Object value) throws RestCallException { 2090 return headers(flag, serializedHeader(name, value, partSerializer, null, EnumSet.of(flag))); 2091 } 2092 2093 /** 2094 * Appends a header on the request. 2095 * 2096 * <h5 class='section'>Example:</h5> 2097 * <p class='bcode w800'> 2098 * <jc>// Adds header "Foo: bar".</jc> 2099 * <jv>client</jv> 2100 * .get(<jsf>URI</jsf>) 2101 * .header(BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>)) 2102 * .run(); 2103 * </p> 2104 * 2105 * @param header The header to set. 2106 * @return This object (for method chaining). 2107 * @throws RestCallException Invalid input. 2108 */ 2109 public RestRequest header(Header header) throws RestCallException { 2110 return headers(header); 2111 } 2112 2113 /** 2114 * Appends multiple headers to the request. 2115 * 2116 * <h5 class='section'>Example:</h5> 2117 * <p class='bcode w800'> 2118 * <jc>// Adds headers "Foo: bar" and "Baz: qux".</jc> 2119 * <jv>client</jv> 2120 * .get(<jsf>URI</jsf>) 2121 * .headers( 2122 * BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>), 2123 * AMap.<jsm>of</jsm>(<js>"Baz"</js>, <js>"qux"</js>) 2124 * ) 2125 * .run(); 2126 * </p> 2127 * 2128 * @param headers 2129 * The headers to set. 2130 * <br>Can be any of the following types: 2131 * <ul> 2132 * <li>{@link Header} (including any subclasses such as {@link Accept}) 2133 * <li>{@link Headerable} 2134 * <li>{@link java.util.Map.Entry} 2135 * <li>{@link HeaderSupplier} 2136 * <li>{@link Map} 2137 * <ul> 2138 * <li>Values can be any POJO. 2139 * <li>Values converted to a string using the configured part serializer. 2140 * </ul> 2141 * <li>A collection or array of anything on this list. 2142 * </ul> 2143 * @return This object (for method chaining). 2144 * @throws RestCallException Invalid input. 2145 */ 2146 public RestRequest headers(Object...headers) throws RestCallException { 2147 return headers(APPEND, headers); 2148 } 2149 2150 /** 2151 * Sets multiple headers on the request. 2152 * 2153 * <h5 class='section'>Example:</h5> 2154 * <p class='bcode w800'> 2155 * <jc>// Adds headers "Foo: bar" and "Baz: qux".</jc> 2156 * <jv>client</jv> 2157 * .get(<jsf>URI</jsf>) 2158 * .headers( 2159 * <jsf>APPEND</jsf>, 2160 * BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>), 2161 * AMap.<jsm>of</jsm>(<js>"Baz"</js>, <js>"qux"</js>) 2162 * ) 2163 * .run(); 2164 * </p> 2165 * 2166 * @param flag How to add this parameter. 2167 * <ul> 2168 * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. 2169 * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. 2170 * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. 2171 * </ul> 2172 * @param headers 2173 * The headers to set. 2174 * <br>Can be any of the following types: 2175 * <ul> 2176 * <li>{@link Header} (including any subclasses such as {@link Accept}) 2177 * <li>{@link Headerable} 2178 * <li>{@link java.util.Map.Entry} 2179 * <li>{@link HeaderSupplier} 2180 * <li>{@link Map} 2181 * <ul> 2182 * <li>Values can be any POJO. 2183 * <li>Values converted to a string using the configured part serializer. 2184 * </ul> 2185 * <li>A collection or array of anything on this list. 2186 * </ul> 2187 * @return This object (for method chaining). 2188 * @throws RestCallException Invalid input. 2189 */ 2190 public RestRequest headers(AddFlag flag, Object...headers) throws RestCallException { 2191 List<Header> l = new ArrayList<>(); 2192 for (Object o : headers) { 2193 if (BasicHeader.canCast(o)) { 2194 l.add(BasicHeader.cast(o)); 2195 } else if (o instanceof HeaderSupplier) { 2196 for (Header h : (HeaderSupplier)o) 2197 l.add(h); 2198 } else if (o instanceof Collection) { 2199 for (Object o2 : (Collection<?>)o) 2200 l.add(BasicHeader.cast(o2)); 2201 } else if (o != null && o.getClass().isArray()) { 2202 for (int i = 0; i < Array.getLength(o); i++) 2203 l.add(BasicHeader.cast(Array.get(o, i))); 2204 } else if (o instanceof Map) { 2205 for (Map.Entry<Object,Object> e : toMap(o).entrySet()) 2206 l.add(serializedHeader(e.getKey(), e.getValue(), partSerializer, null, EnumSet.of(flag))); 2207 } else if (isBean(o)) { 2208 for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) 2209 l.add(serializedHeader(e.getKey(), e.getValue(), partSerializer, null, EnumSet.of(flag))); 2210 } else if (o != null) { 2211 throw new RestCallException(null, null, "Invalid type passed to headers(): {0}", className(o)); 2212 } 2213 } 2214 return innerHeaders(EnumSet.of(flag), l); 2215 } 2216 2217 /** 2218 * Appends multiple headers on the request using freeform key/value pairs. 2219 * 2220 * <h5 class='section'>Example:</h5> 2221 * <p class='bcode w800'> 2222 * <jc>// Adds headers "Foo: bar" and "Baz: qux".</jc> 2223 * <jv>client</jv> 2224 * .get(<jsf>URI</jsf>) 2225 * .headers(<js>"Foo"</js>,<js>"bar"</js>,<js>"Baz"</js>,<js>"qux"</js>) 2226 * .run(); 2227 * </p> 2228 * 2229 * @param pairs The form-data key/value pairs. 2230 * <ul> 2231 * <li>Values can be any POJO. 2232 * <li>Values converted to a string using the configured part serializer. 2233 * </ul> 2234 * @return This object (for method chaining). 2235 * @throws RestCallException Invalid input. 2236 */ 2237 public RestRequest headerPairs(Object...pairs) throws RestCallException { 2238 List<Header> l = new ArrayList<>(); 2239 if (pairs.length % 2 != 0) 2240 throw new RestCallException(null, null, "Odd number of parameters passed into headerPairs()"); 2241 for (int i = 0; i < pairs.length; i+=2) 2242 l.add(serializedHeader(pairs[i], pairs[i+1], partSerializer, null, null)); 2243 return innerHeaders(EnumSet.of(APPEND), l); 2244 } 2245 2246 RestRequest headerArg(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { 2247 flags = AddFlag.orDefault(flags); 2248 boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof HeaderSupplier || isHeaderArray(value); 2249 2250 if (! isMulti) 2251 return innerHeaders(flags, AList.of(serializedHeader(name, value, serializer, schema, flags))); 2252 2253 List<Header> l = AList.of(); 2254 2255 if (BasicHeader.canCast(value)) { 2256 l.add(BasicHeader.cast(value)); 2257 } else if (value instanceof HeaderSupplier) { 2258 for (Object o : (HeaderSupplier)value) 2259 l.add(BasicHeader.cast(o)); 2260 } else if (value instanceof Collection) { 2261 for (Object o : (Collection<?>)value) 2262 l.add(BasicHeader.cast(o)); 2263 } else if (value != null && value.getClass().isArray()) { 2264 for (int i = 0; i < Array.getLength(value); i++) 2265 l.add(BasicHeader.cast(Array.get(value, i))); 2266 } else if (value instanceof Map) { 2267 for (Map.Entry<Object,Object> e : toMap(value).entrySet()) 2268 l.add(serializedHeader(e.getKey(), e.getValue(), serializer, schema, flags)); 2269 } else if (isBean(value)) { 2270 for (Map.Entry<String,Object> e : toBeanMap(value).entrySet()) 2271 l.add(serializedHeader(e.getKey(), e.getValue(), serializer, schema, flags)); 2272 } else if (value != null) { 2273 throw new RestCallException(null, null, "Invalid value type for header arg ''{0}'': {1}", name, className(value)); 2274 } 2275 2276 return innerHeaders(flags, l); 2277 } 2278 2279 private RestRequest innerHeaders(EnumSet<AddFlag> flags, Collection<Header> headers) { 2280 flags = AddFlag.orDefault(flags); 2281 headers.removeIf(x -> x.getValue() == null); 2282 if (flags.contains(SKIP_IF_EMPTY)) 2283 headers.removeIf(x -> isEmpty(x.getValue())); 2284 if (flags.contains(REPLACE)) { 2285 for (Header h : headers) 2286 removeHeaders(h.getName()); 2287 } else if (flags.contains(PREPEND)) { 2288 for (Header h : AList.of(headers)) { 2289 for (Header h2 : getHeaders(h.getName())) 2290 headers.add(h2); 2291 removeHeaders(h.getName()); 2292 } 2293 } 2294 for (Header h : headers) { 2295 addHeader(h); 2296 } 2297 return this; 2298 } 2299 2300 /** 2301 * Convenience method for reading the current last value of the specified header. 2302 * 2303 * @param name The header name. 2304 * @return The header value or <jk>null</jk> if not set. 2305 */ 2306 public String getHeader(String name) { 2307 return getHeader(name, null); 2308 } 2309 2310 /** 2311 * Convenience method for reading the current last value of the specified header. 2312 * 2313 * @param name The header name. 2314 * @param def The default value if the header is not set. 2315 * @return The header value or the default value if not set. 2316 */ 2317 public String getHeader(String name, String def) { 2318 Header h = getLastHeader(name); 2319 return h == null ? def : h.getValue(); 2320 } 2321 2322 //------------------------------------------------------------------------------------------------------------------ 2323 // Specialized headers. 2324 //------------------------------------------------------------------------------------------------------------------ 2325 2326 /** 2327 * Sets the value for the <c>Accept</c> request header. 2328 * 2329 * <p> 2330 * This overrides the media type specified on the parser, but is overridden by calling 2331 * <code>header(<js>"Accept"</js>, value);</code> 2332 * 2333 * @param value The new header value. 2334 * @return This object (for method chaining). 2335 * @throws RestCallException Invalid input. 2336 */ 2337 public RestRequest accept(Object value) throws RestCallException { 2338 return header("Accept", value); 2339 } 2340 2341 /** 2342 * Sets the value for the <c>Accept-Charset</c> request header. 2343 * 2344 * <p> 2345 * This is a shortcut for calling <code>header(<js>"Accept-Charset"</js>, value);</code> 2346 * 2347 * @param value The new header value. 2348 * @return This object (for method chaining). 2349 * @throws RestCallException Invalid input. 2350 */ 2351 public RestRequest acceptCharset(Object value) throws RestCallException { 2352 return header("Accept-Charset", value); 2353 } 2354 2355 /** 2356 * Sets the value for the <c>Accept-Encoding</c> request header. 2357 * 2358 * <p> 2359 * This is a shortcut for calling <code>header(<js>"Accept-Encoding"</js>, value);</code> 2360 * 2361 * @param value The new header value. 2362 * @return This object (for method chaining). 2363 * @throws RestCallException Invalid input. 2364 */ 2365 public RestRequest acceptEncoding(Object value) throws RestCallException { 2366 return header("Accept-Encoding", value); 2367 } 2368 2369 /** 2370 * Sets the value for the <c>Accept-Language</c> request header. 2371 * 2372 * <p> 2373 * This is a shortcut for calling <code>header(<js>"Accept-Language"</js>, value);</code> 2374 * 2375 * @param value The new header value. 2376 * @return This object (for method chaining). 2377 * @throws RestCallException Invalid input. 2378 */ 2379 public RestRequest acceptLanguage(Object value) throws RestCallException { 2380 return header("Accept-Language", value); 2381 } 2382 2383 /** 2384 * Sets the value for the <c>Authorization</c> request header. 2385 * 2386 * <p> 2387 * This is a shortcut for calling <code>header(<js>"Authorization"</js>, value);</code> 2388 * 2389 * @param value The new header value. 2390 * @return This object (for method chaining). 2391 * @throws RestCallException Invalid input. 2392 */ 2393 public RestRequest authorization(Object value) throws RestCallException { 2394 return header("Authorization", value); 2395 } 2396 2397 /** 2398 * Sets the value for the <c>Cache-Control</c> request header. 2399 * 2400 * <p> 2401 * This is a shortcut for calling <code>header(<js>"Cache-Control"</js>, value);</code> 2402 * 2403 * @param value The new header value. 2404 * @return This object (for method chaining). 2405 * @throws RestCallException Invalid input. 2406 */ 2407 public RestRequest cacheControl(Object value) throws RestCallException { 2408 return header("Cache-Control", value); 2409 } 2410 2411 /** 2412 * Sets the value for the <c>Connection</c> request header. 2413 * 2414 * <p> 2415 * This is a shortcut for calling <code>header(<js>"Connection"</js>, value);</code> 2416 * 2417 * @param value The new header value. 2418 * @return This object (for method chaining). 2419 * @throws RestCallException Invalid input. 2420 */ 2421 public RestRequest connection(Object value) throws RestCallException { 2422 return header("Connection", value); 2423 } 2424 2425 /** 2426 * Sets the value for the <c>Content-Length</c> request header. 2427 * 2428 * <p> 2429 * This is a shortcut for calling <code>header(<js>"Content-Length"</js>, value);</code> 2430 * 2431 * @param value The new header value. 2432 * @return This object (for method chaining). 2433 * @throws RestCallException Invalid input. 2434 */ 2435 public RestRequest contentLength(Object value) throws RestCallException { 2436 return header("Content-Length", value); 2437 } 2438 2439 /** 2440 * Sets the value for the <c>Content-Type</c> request header. 2441 * 2442 * <p> 2443 * This overrides the media type specified on the serializer, but is overridden by calling 2444 * <code>header(<js>"Content-Type"</js>, value);</code> 2445 * 2446 * @param value The new header value. 2447 * @return This object (for method chaining). 2448 * @throws RestCallException Invalid input. 2449 */ 2450 public RestRequest contentType(Object value) throws RestCallException { 2451 return header("Content-Type", value); 2452 } 2453 2454 /** 2455 * Sets the value for the <c>Content-Encoding</c> request header. 2456 * 2457 * <p> 2458 * This is a shortcut for calling <code>header(<js>"Content-Encoding"</js>, value);</code> 2459 * 2460 * @param value The new header value. 2461 * @return This object (for method chaining). 2462 * @throws RestCallException Invalid input. 2463 */ 2464 public RestRequest contentEncoding(Object value) throws RestCallException { 2465 return header("Content-Encoding", value); 2466 } 2467 2468 /** 2469 * Sets the value for the <c>Date</c> request header. 2470 * 2471 * <p> 2472 * This is a shortcut for calling <code>header(<js>"Date"</js>, value);</code> 2473 * 2474 * @param value The new header value. 2475 * @return This object (for method chaining). 2476 * @throws RestCallException Invalid input. 2477 */ 2478 public RestRequest date(Object value) throws RestCallException { 2479 return header("Date", value); 2480 } 2481 2482 /** 2483 * Sets the value for the <c>Expect</c> request header. 2484 * 2485 * <p> 2486 * This is a shortcut for calling <code>header(<js>"Expect"</js>, value);</code> 2487 * 2488 * @param value The new header value. 2489 * @return This object (for method chaining). 2490 * @throws RestCallException Invalid input. 2491 */ 2492 public RestRequest expect(Object value) throws RestCallException { 2493 return header("Expect", value); 2494 } 2495 2496 /** 2497 * Sets the value for the <c>Forwarded</c> request header. 2498 * 2499 * <p> 2500 * This is a shortcut for calling <code>header(<js>"Forwarded"</js>, value);</code> 2501 * 2502 * @param value The new header value. 2503 * @return This object (for method chaining). 2504 * @throws RestCallException Invalid input. 2505 */ 2506 public RestRequest forwarded(Object value) throws RestCallException { 2507 return header("Forwarded", value); 2508 } 2509 2510 /** 2511 * Sets the value for the <c>From</c> request header. 2512 * 2513 * <p> 2514 * This is a shortcut for calling <code>header(<js>"From"</js>, value);</code> 2515 * 2516 * @param value The new header value. 2517 * @return This object (for method chaining). 2518 * @throws RestCallException Invalid input. 2519 */ 2520 public RestRequest from(Object value) throws RestCallException { 2521 return header("From", value); 2522 } 2523 2524 /** 2525 * Sets the value for the <c>Host</c> request header. 2526 * 2527 * <p> 2528 * This is a shortcut for calling <code>header(<js>"Host"</js>, value);</code> 2529 * 2530 * @param value The new header value. 2531 * @return This object (for method chaining). 2532 * @throws RestCallException Invalid input. 2533 */ 2534 public RestRequest hostHeader(Object value) throws RestCallException { 2535 return header("Host", value); 2536 } 2537 2538 /** 2539 * Sets the value for the <c>If-Match</c> request header. 2540 * 2541 * <p> 2542 * This is a shortcut for calling <code>header(<js>"If-Match"</js>, value);</code> 2543 * 2544 * @param value The new header value. 2545 * @return This object (for method chaining). 2546 * @throws RestCallException Invalid input. 2547 */ 2548 public RestRequest ifMatch(Object value) throws RestCallException { 2549 return header("If-Match", value); 2550 } 2551 2552 /** 2553 * Sets the value for the <c>If-Modified-Since</c> request header. 2554 * 2555 * <p> 2556 * This is a shortcut for calling <code>header(<js>"If-Modified-Since"</js>, value);</code> 2557 * 2558 * @param value The new header value. 2559 * @return This object (for method chaining). 2560 * @throws RestCallException Invalid input. 2561 */ 2562 public RestRequest ifModifiedSince(Object value) throws RestCallException { 2563 return header("If-Modified-Since", value); 2564 } 2565 2566 /** 2567 * Sets the value for the <c>If-None-Match</c> request header. 2568 * 2569 * <p> 2570 * This is a shortcut for calling <code>header(<js>"If-None-Match"</js>, value);</code> 2571 * 2572 * @param value The new header value. 2573 * @return This object (for method chaining). 2574 * @throws RestCallException Invalid input. 2575 */ 2576 public RestRequest ifNoneMatch(Object value) throws RestCallException { 2577 return header("If-None-Match", value); 2578 } 2579 2580 /** 2581 * Sets the value for the <c>If-Range</c> request header. 2582 * 2583 * <p> 2584 * This is a shortcut for calling <code>header(<js>"If-Range"</js>, value);</code> 2585 * 2586 * @param value The new header value. 2587 * @return This object (for method chaining). 2588 * @throws RestCallException Invalid input. 2589 */ 2590 public RestRequest ifRange(Object value) throws RestCallException { 2591 return header("If-Range", value); 2592 } 2593 2594 /** 2595 * Sets the value for the <c>If-Unmodified-Since</c> request header. 2596 * 2597 * <p> 2598 * This is a shortcut for calling <code>header(<js>"If-Unmodified-Since"</js>, value);</code> 2599 * 2600 * @param value The new header value. 2601 * @return This object (for method chaining). 2602 * @throws RestCallException Invalid input. 2603 */ 2604 public RestRequest ifUnmodifiedSince(Object value) throws RestCallException { 2605 return header("If-Unmodified-Since", value); 2606 } 2607 2608 /** 2609 * Sets the value for the <c>Max-Forwards</c> request header. 2610 * 2611 * <p> 2612 * This is a shortcut for calling <code>header(<js>"Max-Forwards"</js>, value);</code> 2613 * 2614 * @param value The new header value. 2615 * @return This object (for method chaining). 2616 * @throws RestCallException Invalid input. 2617 */ 2618 public RestRequest maxForwards(Object value) throws RestCallException { 2619 return header("Max-Forwards", value); 2620 } 2621 2622 /** 2623 * When called, <c>No-Trace: true</c> is added to requests. 2624 * 2625 * <p> 2626 * This gives the opportunity for the servlet to not log errors on invalid requests. 2627 * This is useful for testing purposes when you don't want your log file to show lots of errors that are simply the 2628 * results of testing. 2629 * 2630 * @return This object (for method chaining). 2631 * @throws RestCallException Invalid input. 2632 */ 2633 public RestRequest noTrace() throws RestCallException { 2634 return header("No-Trace", true); 2635 } 2636 2637 /** 2638 * Sets the value for the <c>Origin</c> request header. 2639 * 2640 * <p> 2641 * This is a shortcut for calling <code>header(<js>"Origin"</js>, value);</code> 2642 * 2643 * @param value The new header value. 2644 * @return This object (for method chaining). 2645 * @throws RestCallException Invalid input. 2646 */ 2647 public RestRequest origin(Object value) throws RestCallException { 2648 return header("Origin", value); 2649 } 2650 2651 /** 2652 * Sets the value for the <c>Pragma</c> request header. 2653 * 2654 * <p> 2655 * This is a shortcut for calling <code>header(<js>"Pragma"</js>, value);</code> 2656 * 2657 * @param value The new header value. 2658 * @return This object (for method chaining). 2659 * @throws RestCallException Invalid input. 2660 */ 2661 public RestRequest pragma(Object value) throws RestCallException { 2662 return header("Pragma", value); 2663 } 2664 2665 /** 2666 * Sets the value for the <c>Proxy-Authorization</c> request header. 2667 * 2668 * <p> 2669 * This is a shortcut for calling <code>header(<js>"Proxy-Authorization"</js>, value);</code> 2670 * 2671 * @param value The new header value. 2672 * @return This object (for method chaining). 2673 * @throws RestCallException Invalid input. 2674 */ 2675 public RestRequest proxyAuthorization(Object value) throws RestCallException { 2676 return header("Proxy-Authorization", value); 2677 } 2678 2679 /** 2680 * Sets the value for the <c>Range</c> request header. 2681 * 2682 * <p> 2683 * This is a shortcut for calling <code>header(<js>"Range"</js>, value);</code> 2684 * 2685 * @param value The new header value. 2686 * @return This object (for method chaining). 2687 * @throws RestCallException Invalid input. 2688 */ 2689 public RestRequest range(Object value) throws RestCallException { 2690 return header("Range", value); 2691 } 2692 2693 /** 2694 * Sets the value for the <c>Referer</c> request header. 2695 * 2696 * <p> 2697 * This is a shortcut for calling <code>header(<js>"Referer"</js>, value);</code> 2698 * 2699 * @param value The new header value. 2700 * @return This object (for method chaining). 2701 * @throws RestCallException Invalid input. 2702 */ 2703 public RestRequest referer(Object value) throws RestCallException { 2704 return header("Referer", value); 2705 } 2706 2707 /** 2708 * Sets the value for the <c>TE</c> request header. 2709 * 2710 * <p> 2711 * This is a shortcut for calling <code>header(<js>"TE"</js>, value);</code> 2712 * 2713 * @param value The new header value. 2714 * @return This object (for method chaining). 2715 * @throws RestCallException Invalid input. 2716 */ 2717 public RestRequest te(Object value) throws RestCallException { 2718 return header("TE", value); 2719 } 2720 2721 /** 2722 * Sets the value for the <c>User-Agent</c> request header. 2723 * 2724 * <p> 2725 * This is a shortcut for calling <code>header(<js>"User-Agent"</js>, value);</code> 2726 * 2727 * @param value The new header value. 2728 * @return This object (for method chaining). 2729 * @throws RestCallException Invalid input. 2730 */ 2731 public RestRequest userAgent(Object value) throws RestCallException { 2732 return header("User-Agent", value); 2733 } 2734 2735 /** 2736 * Sets the value for the <c>Upgrade</c> request header. 2737 * 2738 * <p> 2739 * This is a shortcut for calling <code>header(<js>"Upgrade"</js>, value);</code> 2740 * 2741 * @param value The new header value. 2742 * @return This object (for method chaining). 2743 * @throws RestCallException Invalid input. 2744 */ 2745 public RestRequest upgrade(Object value) throws RestCallException { 2746 return header("Upgrade", value); 2747 } 2748 2749 /** 2750 * Sets the value for the <c>Via</c> request header. 2751 * 2752 * <p> 2753 * This is a shortcut for calling <code>header(<js>"Via"</js>, value);</code> 2754 * 2755 * @param value The new header value. 2756 * @return This object (for method chaining). 2757 * @throws RestCallException Invalid input. 2758 */ 2759 public RestRequest via(Object value) throws RestCallException { 2760 return header("Via", value); 2761 } 2762 2763 /** 2764 * Sets the value for the <c>Warning</c> request header. 2765 * 2766 * <p> 2767 * This is a shortcut for calling <code>header(<js>"Warning"</js>, value);</code> 2768 * 2769 * @param value The new header value. 2770 * @return This object (for method chaining). 2771 * @throws RestCallException Invalid input. 2772 */ 2773 public RestRequest warning(Object value) throws RestCallException { 2774 return header("Warning", value); 2775 } 2776 2777 /** 2778 * Sets the client version by setting the value for the <js>"X-Client-Version"</js> header. 2779 * 2780 * @param value The version string (e.g. <js>"1.2.3"</js>) 2781 * @return This object (for method chaining). 2782 * @throws RestCallException Invalid input. 2783 */ 2784 public RestRequest clientVersion(Object value) throws RestCallException { 2785 return header("X-Client-Version", value); 2786 } 2787 2788 //------------------------------------------------------------------------------------------------------------------ 2789 // Execution methods. 2790 //------------------------------------------------------------------------------------------------------------------ 2791 2792 /** 2793 * Runs this request and returns the resulting response object. 2794 * 2795 * <h5 class='section'>Example:</h5> 2796 * <p class='bcode w800'> 2797 * <jk>try</jk> { 2798 * <jk>int</jk> <jv>rc</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).execute().getResponseStatus(); 2799 * <jc>// Succeeded!</jc> 2800 * } <jk>catch</jk> (RestCallException <jv>e</jv>) { 2801 * <jc>// Failed!</jc> 2802 * } 2803 * </p> 2804 * 2805 * <ul class='notes'> 2806 * <li>Calling this method multiple times will return the same original response object. 2807 * <li>You must close the returned object if you do not consume the response or execute a method that consumes 2808 * the response. 2809 * <li>If you are only interested in the response code, use the {@link #complete()} method which will automatically 2810 * consume the response so that you don't need to call {@link InputStream#close()} on the response body. 2811 * </ul> 2812 * 2813 * @return The response object. 2814 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt. 2815 */ 2816 public RestResponse run() throws RestCallException { 2817 if (response != null) 2818 throw new RestCallException(response, null, "run() already called."); 2819 2820 try { 2821 HttpEntityEnclosingRequestBase request2 = request instanceof HttpEntityEnclosingRequestBase ? (HttpEntityEnclosingRequestBase)request : null; 2822 request.setURI(uriBuilder.build()); 2823 2824 // Pick the serializer if it hasn't been overridden. 2825 Header h = getLastHeader("Content-Type"); 2826 String contentType = h == null ? null : h.getValue(); 2827 Serializer serializer = this.serializer; 2828 if (serializer == null) 2829 serializer = client.getMatchingSerializer(contentType); 2830 if (contentType == null && serializer != null) 2831 contentType = serializer.getPrimaryMediaType().toString(); 2832 2833 // Pick the parser if it hasn't been overridden. 2834 h = getLastHeader("Accept"); 2835 String accept = h == null ? null : h.getValue(); 2836 Parser parser = this.parser; 2837 if (parser == null) 2838 parser = client.getMatchingParser(accept); 2839 if (accept == null && parser != null) 2840 setHeader("Accept", parser.getPrimaryMediaType().toString()); 2841 2842 if (hasInput || formData != null) { 2843 2844 if (request2 == null) 2845 throw new RestCallException(null, null, "Method does not support content entity. Method={0}, URI={1}", getMethod(), getURI()); 2846 2847 Object input2 = input; 2848 2849 if (input2 instanceof Supplier) 2850 input2 = ((Supplier<?>)input).get(); 2851 2852 HttpEntity entity = null; 2853 if (formData != null) 2854 entity = new UrlEncodedFormEntity(formData); 2855 else if (input2 instanceof NameValuePairSupplier) 2856 entity = new UrlEncodedFormEntity((NameValuePairSupplier)input2); 2857 else if (input2 instanceof HttpResource) { 2858 HttpResource r = (HttpResource)input2; 2859 headers(r.getHeaders()); 2860 entity = (HttpEntity)input2; 2861 } 2862 else if (input2 instanceof HttpEntity) 2863 entity = (HttpEntity)input2; 2864 else if (input2 instanceof Reader) 2865 entity = new StringEntity(IOUtils.read((Reader)input2), getRequestContentType(TEXT_PLAIN)); 2866 else if (input2 instanceof InputStream) 2867 entity = new InputStreamEntity((InputStream)input2, getRequestContentType(ContentType.APPLICATION_OCTET_STREAM)); 2868 else if (serializer != null) 2869 entity = SerializedHttpEntity.of(input2, serializer).schema(requestBodySchema).contentType(contentType); 2870 else { 2871 if (input2 == null) 2872 input2 = ""; 2873 entity = new StringEntity(BeanContext.DEFAULT.getClassMetaForObject(input2).toString(input2), getRequestContentType(TEXT_PLAIN)); 2874 } 2875 2876 request2.setEntity(entity); 2877 } 2878 2879 try { 2880 response = client.createResponse(this, client.run(target, request, context), parser); 2881 } catch (Exception e) { 2882 throw e; 2883 } 2884 2885 if (isDebug() || client.logRequests == DetailLevel.FULL) 2886 response.cacheBody(); 2887 2888 for (RestCallInterceptor rci : interceptors) 2889 rci.onConnect(this, response); 2890 client.onConnect(this, response); 2891 2892 String method = getMethod(); 2893 int sc = response.getStatusCode(); 2894 2895 if (errorCodes.test(sc) && ! ignoreErrors) { 2896 throw new RestCallException(response, null, "HTTP method ''{0}'' call to ''{1}'' caused response code ''{2}, {3}''.\nResponse: \n{4}", 2897 method, getURI(), sc, response.getReasonPhrase(), response.getBody().asAbbreviatedString(1000)); 2898 } 2899 2900 } catch (RuntimeException | RestCallException e) { 2901 if (response != null) 2902 response.close(); 2903 throw e; 2904 } catch (Exception e) { 2905 if (response != null) 2906 response.close(); 2907 throw new RestCallException(response, e, "Call failed."); 2908 } 2909 2910 return this.response; 2911 } 2912 2913 /** 2914 * Same as {@link #run()} but allows you to run the call asynchronously. 2915 * 2916 * <h5 class='section'>Example:</h5> 2917 * <p class='bcode w800'> 2918 * Future<RestResponse> <jv>future</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).runFuture(); 2919 * 2920 * <jc>// Do some other stuff</jc> 2921 * 2922 * <jk>try</jk> { 2923 * String <jv>body</jv> = <jv>future</jv>.get().getBody().asString(); 2924 * <jc>// Succeeded!</jc> 2925 * } <jk>catch</jk> (RestCallException <jv>e</jv>) { 2926 * <jc>// Failed!</jc> 2927 * } 2928 * </p> 2929 * 2930 * <ul class='notes'> 2931 * <li>Use the {@link RestClientBuilder#executorService(ExecutorService, boolean)} method to customize the 2932 * executor service used for creating {@link Future Futures}. 2933 * </ul> 2934 * 2935 * @return The HTTP status code. 2936 * @throws RestCallException If the executor service was not defined. 2937 */ 2938 public Future<RestResponse> runFuture() throws RestCallException { 2939 return client.getExecutorService().submit( 2940 new Callable<RestResponse>() { 2941 @Override /* Callable */ 2942 public RestResponse call() throws Exception { 2943 return run(); 2944 } 2945 } 2946 ); 2947 } 2948 2949 /** 2950 * Same as {@link #run()} but immediately calls {@link RestResponse#consume()} to clean up the response. 2951 * 2952 * <p> 2953 * Use this method if you're only interested in the status line of the response and not the response entity. 2954 * Attempts to call any of the methods on the response object that retrieve the body (e.g. {@link RestResponseBody#asReader()} 2955 * will cause a {@link RestCallException} to be thrown. 2956 * 2957 * <ul class='notes'> 2958 * <li>You do not need to execute {@link InputStream#close()} on the response body to consume the response. 2959 * </ul> 2960 * 2961 * <h5 class='section'>Example:</h5> 2962 * <p class='bcode w800'> 2963 * <jc>// Get the response code. 2964 * // No need to call close() on the RestResponse object.</jc> 2965 * <jk>int</jk> <jv>rc</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getResponseCode(); 2966 * </p> 2967 * 2968 * @return The response object. 2969 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt. 2970 */ 2971 public RestResponse complete() throws RestCallException { 2972 return run().consume(); 2973 } 2974 2975 /** 2976 * Same as {@link #complete()} but allows you to run the call asynchronously. 2977 * 2978 * <h5 class='section'>Example:</h5> 2979 * <p class='bcode w800'> 2980 * Future<RestResponse> <jv>future</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).completeFuture(); 2981 * 2982 * <jc>// Do some other stuff</jc> 2983 * 2984 * <jk>int</jk> <jv>rc</jv> = <jv>future</jv>.get().getResponseStatus(); 2985 * </p> 2986 * 2987 * <ul class='notes'> 2988 * <li>Use the {@link RestClientBuilder#executorService(ExecutorService, boolean)} method to customize the 2989 * executor service used for creating {@link Future Futures}. 2990 * <li>You do not need to execute {@link InputStream#close()} on the response body to consume the response. 2991 * </ul> 2992 * 2993 * @return The HTTP status code. 2994 * @throws RestCallException If the executor service was not defined. 2995 */ 2996 public Future<RestResponse> completeFuture() throws RestCallException { 2997 return client.getExecutorService().submit( 2998 new Callable<RestResponse>() { 2999 @Override /* Callable */ 3000 public RestResponse call() throws Exception { 3001 return complete(); 3002 } 3003 } 3004 ); 3005 } 3006 3007 /** 3008 * Returns <jk>true</jk> if this request has a body. 3009 * 3010 * @return <jk>true</jk> if this request has a body. 3011 */ 3012 public boolean hasHttpEntity() { 3013 return request instanceof HttpEntityEnclosingRequestBase; 3014 } 3015 3016 /** 3017 * Returns the body of this request. 3018 * 3019 * @return The body of this request, or <jk>null</jk> if it doesn't have a body. 3020 */ 3021 public HttpEntity getHttpEntity() { 3022 return hasHttpEntity() ? ((HttpEntityEnclosingRequestBase)request).getEntity() : null; 3023 } 3024 3025 /** 3026 * Logs a message. 3027 * 3028 * @param level The log level. 3029 * @param t The throwable cause. 3030 * @param msg The message with {@link MessageFormat}-style arguments. 3031 * @param args The arguments. 3032 * @return This object (for method chaining). 3033 */ 3034 public RestRequest log(Level level, Throwable t, String msg, Object...args) { 3035 client.log(level, t, msg, args); 3036 return this; 3037 } 3038 3039 /** 3040 * Logs a message. 3041 * 3042 * @param level The log level. 3043 * @param msg The message with {@link MessageFormat}-style arguments. 3044 * @param args The arguments. 3045 * @return This object (for method chaining). 3046 */ 3047 public RestRequest log(Level level, String msg, Object...args) { 3048 client.log(level, msg, args); 3049 return this; 3050 } 3051 3052 //----------------------------------------------------------------------------------------------------------------- 3053 // HttpRequestBase pass-through methods. 3054 //----------------------------------------------------------------------------------------------------------------- 3055 3056 /** 3057 * Sets the actual request configuration. 3058 * 3059 * @param value The new value. 3060 * @return This object (for method chaining). 3061 */ 3062 public RestRequest config(RequestConfig value) { 3063 request.setConfig(value); 3064 return this; 3065 } 3066 3067 /** 3068 * Sets {@link Cancellable} for the ongoing operation. 3069 * 3070 * @param cancellable The cancellable object. 3071 * @return This object (for method chaining). 3072 */ 3073 public RestRequest cancellable(Cancellable cancellable) { 3074 request.setCancellable(cancellable); 3075 return this; 3076 } 3077 3078 /** 3079 * Sets the protocol version for this request. 3080 * 3081 * @param version The protocol version for this request. 3082 * @return This object (for method chaining). 3083 */ 3084 public RestRequest protocolVersion(ProtocolVersion version) { 3085 request.setProtocolVersion(version); 3086 return this; 3087 } 3088 3089 /** 3090 * Used in combination with {@link #cancellable(Cancellable)}. 3091 * 3092 * @return This object (for method chaining). 3093 */ 3094 public RestRequest completed() { 3095 request.completed(); 3096 return this; 3097 } 3098 3099 // ----------------------------------------------------------------------------------------------------------------- 3100 // HttpUriRequest pass-through methods. 3101 // ----------------------------------------------------------------------------------------------------------------- 3102 3103 /** 3104 * Returns the HTTP method this request uses, such as GET, PUT, POST, or other. 3105 * 3106 * @return The HTTP method this request uses, such as GET, PUT, POST, or other. 3107 */ 3108 @Override /* HttpUriRequest */ 3109 public String getMethod() { 3110 return request.getMethod(); 3111 } 3112 3113 /** 3114 * Returns the original request URI. 3115 * 3116 * <ul class='notes'> 3117 * <li>URI remains unchanged in the course of request execution and is not updated if the request is redirected to another location. 3118 * </ul> 3119 * 3120 * @return The original request URI. 3121 */ 3122 @Override /* HttpUriRequest */ 3123 public URI getURI() { 3124 return request.getURI(); 3125 } 3126 3127 /** 3128 * Returns the original request URI as a simple string. 3129 * 3130 * <ul class='notes'> 3131 * <li>URI remains unchanged in the course of request execution and is not updated if the request is redirected to another location. 3132 * </ul> 3133 * 3134 * @return The original request URI. 3135 */ 3136 public String getUri() { 3137 return getURI().toString(); 3138 } 3139 3140 /** 3141 * Aborts this http request. Any active execution of this method should return immediately. 3142 * 3143 * If the request has not started, it will abort after the next execution. 3144 * <br>Aborting this request will cause all subsequent executions with this request to fail. 3145 */ 3146 @Override /* HttpUriRequest */ 3147 public void abort() throws UnsupportedOperationException { 3148 request.abort(); 3149 } 3150 3151 @Override /* HttpUriRequest */ 3152 public boolean isAborted() { 3153 return request.isAborted(); 3154 } 3155 3156 /** 3157 * Returns the request line of this request. 3158 * 3159 * @return The request line. 3160 */ 3161 @Override /* HttpRequest */ 3162 public RequestLine getRequestLine() { 3163 return request.getRequestLine(); 3164 } 3165 3166 /** 3167 * Returns the protocol version this message is compatible with. 3168 * 3169 * @return The protocol version. 3170 */ 3171 @Override /* HttpMessage */ 3172 public ProtocolVersion getProtocolVersion() { 3173 return request.getProtocolVersion(); 3174 } 3175 3176 /** 3177 * Checks if a certain header is present in this message. 3178 * 3179 * Header values are ignored. 3180 * 3181 * @param name The header name to check for. 3182 * @return <jk>true</jk> if at least one header with this name is present. 3183 */ 3184 @Override /* HttpMessage */ 3185 public boolean containsHeader(String name) { 3186 return request.containsHeader(name); 3187 } 3188 3189 /** 3190 * Returns all the headers with a specified name of this message. 3191 * 3192 * Header values are ignored. 3193 * <br>Headers are ordered in the sequence they will be sent over a connection. 3194 * 3195 * @param name The name of the headers to return. 3196 * @return The headers whose name property equals name. 3197 */ 3198 @Override /* HttpMessage */ 3199 public Header[] getHeaders(String name) { 3200 return request.getHeaders(name); 3201 } 3202 3203 /** 3204 * Returns the first header with a specified name of this message. 3205 * 3206 * Header values are ignored. 3207 * <br>If there is more than one matching header in the message the first element of {@link #getHeaders(String)} is returned. 3208 * <br>If there is no matching header in the message <jk>null</jk> is returned. 3209 * 3210 * @param name The name of the header to return. 3211 * @return The first header whose name property equals name or <jk>null</jk> if no such header could be found. 3212 */ 3213 @Override /* HttpMessage */ 3214 public Header getFirstHeader(String name) { 3215 return request.getFirstHeader(name); 3216 } 3217 3218 /** 3219 * Returns the last header with a specified name of this message. 3220 * 3221 * Header values are ignored. 3222 * <br>If there is more than one matching header in the message the last element of {@link #getHeaders(String)} is returned. 3223 * <br>If there is no matching header in the message null is returned. 3224 * 3225 * @param name The name of the header to return. 3226 * @return The last header whose name property equals name or <jk>null</jk> if no such header could be found. 3227 */ 3228 @Override /* HttpMessage */ 3229 public Header getLastHeader(String name) { 3230 return request.getLastHeader(name); 3231 } 3232 3233 /** 3234 * Returns all the headers of this message. 3235 * 3236 * Headers are ordered in the sequence they will be sent over a connection. 3237 * 3238 * @return All the headers of this message 3239 */ 3240 @Override /* HttpMessage */ 3241 public Header[] getAllHeaders() { 3242 return request.getAllHeaders(); 3243 } 3244 3245 /** 3246 * Adds a header to this message. 3247 * 3248 * The header will be appended to the end of the list. 3249 * 3250 * <ul class='notes'> 3251 * <li>{@link #header(Header)} is an equivalent method and the preferred method for fluent-style coding. 3252 * </ul> 3253 * 3254 * @param header The header to append. 3255 */ 3256 @Override /* HttpMessage */ 3257 public void addHeader(Header header) { 3258 request.addHeader(header); 3259 } 3260 3261 /** 3262 * Adds a header to this message. 3263 * 3264 * The header will be appended to the end of the list. 3265 * 3266 * <ul class='notes'> 3267 * <li>{@link #header(String,Object)} is an equivalent method and the preferred method for fluent-style coding. 3268 * </ul> 3269 * 3270 * @param name The name of the header. 3271 * @param value The value of the header. 3272 */ 3273 @Override /* HttpMessage */ 3274 public void addHeader(String name, String value) { 3275 request.addHeader(name, value); 3276 } 3277 3278 /** 3279 * Overwrites the first header with the same name. 3280 * 3281 * The new header will be appended to the end of the list, if no header with the given name can be found. 3282 * 3283 * @param header The header to set. 3284 */ 3285 @Override /* HttpMessage */ 3286 public void setHeader(Header header) { 3287 request.setHeader(header); 3288 } 3289 3290 /** 3291 * Overwrites the first header with the same name. 3292 * 3293 * The new header will be appended to the end of the list, if no header with the given name can be found. 3294 * 3295 * @param name The name of the header. 3296 * @param value The value of the header. 3297 */ 3298 @Override /* HttpMessage */ 3299 public void setHeader(String name, String value) { 3300 request.setHeader(name, value); 3301 } 3302 3303 /** 3304 * Overwrites all the headers in the message. 3305 * 3306 * @param headers The array of headers to set. 3307 */ 3308 @Override /* HttpMessage */ 3309 public void setHeaders(Header[] headers) { 3310 request.setHeaders(headers); 3311 } 3312 3313 /** 3314 * Removes a header from this message. 3315 * 3316 * @param header The header to remove. 3317 */ 3318 @Override /* HttpMessage */ 3319 public void removeHeader(Header header) { 3320 request.removeHeader(header); 3321 } 3322 3323 /** 3324 * Removes all headers with a certain name from this message. 3325 * 3326 * @param name The name of the headers to remove. 3327 */ 3328 @Override /* HttpMessage */ 3329 public void removeHeaders(String name) { 3330 request.removeHeaders(name); 3331 } 3332 3333 /** 3334 * Returns an iterator of all the headers. 3335 * 3336 * @return Iterator that returns {@link Header} objects in the sequence they are sent over a connection. 3337 */ 3338 @Override /* HttpMessage */ 3339 public HeaderIterator headerIterator() { 3340 return request.headerIterator(); 3341 } 3342 3343 /** 3344 * Returns an iterator of the headers with a given name. 3345 * 3346 * @param name the name of the headers over which to iterate, or <jk>null</jk> for all headers. 3347 * @return Iterator that returns {@link Header} objects with the argument name in the sequence they are sent over a connection. 3348 */ 3349 @Override /* HttpMessage */ 3350 public HeaderIterator headerIterator(String name) { 3351 return request.headerIterator(name); 3352 } 3353 3354 /** 3355 * Returns the parameters effective for this message as set by {@link #setParams(HttpParams)}. 3356 * 3357 * @return The parameters effective for this message as set by {@link #setParams(HttpParams)}. 3358 * @deprecated Use constructor parameters of configuration API provided by HttpClient. 3359 */ 3360 @Override /* HttpMessage */ 3361 @Deprecated 3362 public HttpParams getParams() { 3363 return request.getParams(); 3364 } 3365 3366 /** 3367 * Provides parameters to be used for the processing of this message. 3368 * 3369 * @param params The parameters. 3370 * @deprecated Use constructor parameters of configuration API provided by HttpClient. 3371 */ 3372 @Override /* HttpMessage */ 3373 @Deprecated 3374 public void setParams(HttpParams params) { 3375 request.setParams(params); 3376 } 3377 3378 /** 3379 * Returns the actual request configuration. 3380 * 3381 * @return The actual request configuration. 3382 */ 3383 @Override /* Configurable */ 3384 public RequestConfig getConfig() { 3385 return request.getConfig(); 3386 } 3387 3388 // ----------------------------------------------------------------------------------------------------------------- 3389 // Utility methods 3390 // ----------------------------------------------------------------------------------------------------------------- 3391 3392 private ContentType getRequestContentType(ContentType def) { 3393 Header h = request.getFirstHeader("Content-Type"); 3394 if (h != null) { 3395 String s = h.getValue(); 3396 if (! isEmpty(s)) 3397 return ContentType.create(s); 3398 } 3399 return def; 3400 } 3401 3402 @Override 3403 public OMap getProperties() { 3404 return super.getProperties(); 3405 } 3406 3407 @SuppressWarnings("unchecked") 3408 private static Map<Object,Object> toMap(Object o) { 3409 return (Map<Object,Object>)o; 3410 } 3411 3412 private static SerializedNameValuePair serializedNameValuePair(Object key, Object value, HttpPartType type, HttpPartSerializerSession serializer, HttpPartSchema schema, EnumSet<AddFlag> flags) { 3413 return key == null ? null : new SerializedNameValuePair(stringify(key), value, type, serializer, schema, flags == null ? false : flags.contains(SKIP_IF_EMPTY)); 3414 } 3415 3416 private static SerializedHeader serializedHeader(Object key, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema, EnumSet<AddFlag> flags) { 3417 return key == null ? null : new SerializedHeader(stringify(key), value, serializer, schema, flags == null ? false : flags.contains(SKIP_IF_EMPTY)); 3418 } 3419 3420 private static boolean isNameValuePairArray(Object o) { 3421 if (o == null || ! o.getClass().isArray()) 3422 return false; 3423 if (NameValuePair.class.isAssignableFrom(o.getClass().getComponentType())) 3424 return true; 3425 return false; 3426 } 3427 3428 private static boolean isHeaderArray(Object o) { 3429 if (o == null || ! o.getClass().isArray()) 3430 return false; 3431 if (Header.class.isAssignableFrom(o.getClass().getComponentType())) 3432 return true; 3433 return false; 3434 } 3435 3436 //----------------------------------------------------------------------------------------------------------------- 3437 // Other methods 3438 //----------------------------------------------------------------------------------------------------------------- 3439 3440 @Override /* Session */ 3441 public OMap toMap() { 3442 return super.toMap() 3443 .a("RestCall", new DefaultFilteringOMap() 3444 .a("client", client) 3445 .a("hasInput", hasInput) 3446 .a("ignoreErrors", ignoreErrors) 3447 .a("interceptors", interceptors) 3448 .a("partSerializer", partSerializer) 3449 .a("requestBodySchema", requestBodySchema) 3450 .a("response", response) 3451 .a("serializer", serializer) 3452 ); 3453 } 3454}