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.client;
014
015import static org.apache.juneau.internal.IOUtils.*;
016import static org.apache.juneau.internal.StringUtils.*;
017import static org.apache.juneau.httppart.HttpPartType.*;
018import static org.apache.http.HttpStatus.*;
019
020import java.io.*;
021import java.lang.reflect.*;
022import java.lang.reflect.Proxy;
023import java.net.*;
024import java.util.*;
025import java.util.concurrent.*;
026import java.util.logging.*;
027import java.util.regex.*;
028
029import org.apache.http.*;
030import org.apache.http.Header;
031import org.apache.http.client.*;
032import org.apache.http.client.config.*;
033import org.apache.http.client.entity.*;
034import org.apache.http.client.methods.*;
035import org.apache.http.client.utils.*;
036import org.apache.http.conn.*;
037import org.apache.http.entity.*;
038import org.apache.http.entity.ContentType;
039import org.apache.http.impl.client.*;
040import org.apache.http.util.*;
041import org.apache.juneau.*;
042import org.apache.juneau.encoders.*;
043import org.apache.juneau.http.*;
044import org.apache.juneau.http.annotation.*;
045import org.apache.juneau.httppart.*;
046import org.apache.juneau.httppart.bean.*;
047import org.apache.juneau.internal.*;
048import org.apache.juneau.oapi.*;
049import org.apache.juneau.parser.*;
050import org.apache.juneau.parser.ParseException;
051import org.apache.juneau.reflect.*;
052import org.apache.juneau.serializer.*;
053import org.apache.juneau.utils.*;
054
055/**
056 * Represents a connection to a remote REST resource.
057 *
058 * <p>
059 * Instances of this class are created by the various {@code doX()} methods on the {@link RestClient} class.
060 *
061 * <p>
062 * This class uses only Java standard APIs.  Requests can be built up using a fluent interface with method chaining,
063 * like so...
064 * <p class='bcode w800'>
065 *    RestClient client = <jk>new</jk> RestClient();
066 *    RestCall c = client.doPost(<jsf>URL</jsf>).setInput(o).setHeader(x,y);
067 *    MyBean b = c.getResponse(MyBean.<jk>class</jk>);
068 * </p>
069 *
070 * <p>
071 * The actual connection and request/response transaction occurs when calling one of the <c>getResponseXXX()</c>
072 * methods.
073 *
074 * <ul class='seealso'>
075 *    <li class='link'>{@doc juneau-rest-client}
076 * </ul>
077 */
078@SuppressWarnings({ "unchecked" })
079public final class RestCall extends BeanSession implements Closeable {
080
081   private static final ContentType TEXT_PLAIN = ContentType.create("text/plain");
082
083   private final RestClient client;                       // The client that created this call.
084   private final HttpRequestBase request;                 // The request.
085   private HttpResponse response;                         // The response.
086   private List<RestCallInterceptor> interceptors = new ArrayList<>();               // Used for intercepting and altering requests.
087
088   private boolean isConnected = false;                   // connect() has been called.
089   private boolean allowRedirectsOnPosts;
090   private int retries = 1;
091   private int redirectOnPostsTries = 5;
092   private long retryInterval = -1;
093   private RetryOn retryOn;
094   private boolean ignoreErrors;
095   private boolean byLines = false;
096   private TeeWriter writers = new TeeWriter();
097   private StringWriter capturedResponseWriter;
098   private String capturedResponse;
099   private TeeOutputStream outputStreams = new TeeOutputStream();
100   private boolean isClosed = false;
101   private boolean isFailed = false;
102   private Object input;
103   private boolean hasInput;  // input() was called, even if it's setting 'null'.
104   private Serializer serializer;
105   private Parser parser;
106   private HttpPartSerializer partSerializer;
107   private HttpPartParser partParser;
108   private HttpPartSchema requestBodySchema, responseBodySchema;
109   private URIBuilder uriBuilder;
110   private NameValuePairs formData;
111   private boolean softClose = false;  // If true, don't consume response and set isClosed flag, but do call listeners.
112
113   /**
114    * Constructs a REST call with the specified method name.
115    *
116    * @param client The client that created this request.
117    * @param request The wrapped Apache HTTP client request object.
118    * @param uri The URI for this call.
119    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
120    */
121   protected RestCall(RestClient client, HttpRequestBase request, URI uri) throws RestCallException {
122      super(client, BeanSessionArgs.DEFAULT);
123      this.client = client;
124      this.request = request;
125      for (RestCallInterceptor i : this.client.interceptors)
126         interceptor(i);
127      this.retryOn = client.retryOn;
128      this.retries = client.retries;
129      this.retryInterval = client.retryInterval;
130      this.serializer = client.serializer;
131      this.parser = client.parser;
132      this.partSerializer = client.getPartSerializer();
133      this.partParser = client.getPartParser();
134      uriBuilder = new URIBuilder(uri);
135   }
136
137   /**
138    * Sets the URI for this call.
139    *
140    * <p>
141    * Can be any of the following types:
142    * <ul>
143    *    <li>{@link URI}
144    *    <li>{@link URL}
145    *    <li>{@link URIBuilder}
146    *    <li>Anything else converted to a string using {@link Object#toString()}.
147    * </ul>
148    *
149    * <p>
150    * Relative URL strings will be interpreted as relative to the root URL defined on the client.
151    *
152    * @param uri
153    *    The URI to use for this call.
154    *    This overrides the URI passed in from the client.
155    * @return This object (for method chaining).
156    * @throws RestCallException Invalid URI syntax detected.
157    */
158   public RestCall uri(Object uri) throws RestCallException {
159      try {
160         if (uri != null)
161            uriBuilder = new URIBuilder(client.toURI(uri));
162         return this;
163      } catch (URISyntaxException e) {
164         throw new RestCallException(e);
165      }
166   }
167
168   /**
169    * Sets the URI scheme.
170    *
171    * @param scheme The new URI host.
172    * @return This object (for method chaining).
173    */
174   public RestCall scheme(String scheme) {
175      uriBuilder.setScheme(scheme);
176      return this;
177   }
178
179   /**
180    * Sets the URI host.
181    *
182    * @param host The new URI host.
183    * @return This object (for method chaining).
184    */
185   public RestCall host(String host) {
186      uriBuilder.setHost(host);
187      return this;
188   }
189
190   /**
191    * Sets the URI port.
192    *
193    * @param port The new URI port.
194    * @return This object (for method chaining).
195    */
196   public RestCall port(int port) {
197      uriBuilder.setPort(port);
198      return this;
199   }
200
201   /**
202    * Adds a query parameter to the URI query.
203    *
204    * @param name
205    *    The parameter name.
206    *    Can be null/blank/* if the value is a {@link Map}, {@link String}, {@link NameValuePairs}, or bean.
207    * @param value
208    *    The parameter value converted to a string using UON notation.
209    *    Can also be {@link Map}, {@link String}, {@link NameValuePairs}, or bean if the name is null/blank/*.
210    *    If a {@link String} and the name is null/blank/*, then calls {@link URIBuilder#setCustomQuery(String)}.
211    * @param skipIfEmpty Don't add the pair if the value is empty.
212    * @param serializer
213    *    The serializer to use for serializing the value to a string value.
214    *    If <jk>null</jk>, then the URL-encoding serializer defined on the client is used.
215    * @param schema
216    *    The schema object that defines the format of the output.
217    *    <br>If <jk>null</jk>, defaults to the schema defined on the serializer.
218    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
219    *    <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}).
220    * @return This object (for method chaining).
221    * @throws RestCallException Error occurred.
222    */
223   public RestCall query(String name, Object value, boolean skipIfEmpty, HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
224      if (serializer == null)
225         serializer = client.getPartSerializer();
226      if (schema == null)
227         schema = HttpPartSchema.DEFAULT;
228      boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairs;
229      if (! isMulti) {
230         if (canAdd(value, schema, skipIfEmpty))
231            try {
232               uriBuilder.addParameter(name, serializer.serialize(QUERY, schema, value));
233            } catch (SchemaValidationException e) {
234               throw new RestCallException(e, "Validation error on request query parameter ''{0}''=''{1}''", name, value);
235            } catch (SerializeException e) {
236               throw new RestCallException(e, "Serialization error on request query parameter ''{0}''", name);
237            }
238      } else if (value instanceof NameValuePairs) {
239         for (NameValuePair p : (NameValuePairs)value) {
240            String n = p.getName();
241            String v = p.getValue();
242            HttpPartSchema s = schema.getProperty(n);
243            if (canAdd(v, s, skipIfEmpty))
244               query(n, v, skipIfEmpty, serializer, s);
245         }
246      } else if (value instanceof Map) {
247         for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet()) {
248            String n = p.getKey();
249            Object v = p.getValue();
250            HttpPartSchema s = schema.getProperty(n);
251            if (canAdd(v, s, skipIfEmpty))
252               query(n, v, skipIfEmpty, serializer, s);
253         }
254      } else if (isBean(value)) {
255         return query(name, toBeanMap(value), skipIfEmpty, serializer, schema);
256      } else if (value instanceof Reader || value instanceof InputStream) {
257         try {
258            uriBuilder.setCustomQuery(read(value));
259         } catch (IOException e) {
260            throw new RestCallException(e);
261         }
262      } else if (value instanceof CharSequence) {
263         String s = value.toString();
264         if (isNotEmpty(s))
265            uriBuilder.setCustomQuery(s);
266      } else {
267         throw new RestCallException("Invalid name ''{0}'' passed to query(name,value,skipIfEmpty) for data type ''{1}''", name, className(value));
268      }
269      return this;
270   }
271
272   /**
273    * Adds a query parameter to the URI query.
274    *
275    * @param name The parameter name.
276    * @param value The parameter value converted to a string using UON notation.
277    * @return This object (for method chaining).
278    * @throws RestCallException Invalid input.
279    */
280   public RestCall query(String name, Object value) throws RestCallException {
281      return query(name, value, false, null, null);
282   }
283
284   /**
285    * Adds query parameters to the URI query.
286    *
287    * @param params The parameters.  Values are converted to a string using UON notation.
288    * @return This object (for method chaining).
289    * @throws RestCallException Invalid input.
290    */
291   public RestCall query(Map<String,Object> params) throws RestCallException {
292      return query(null, params);
293   }
294
295   /**
296    * Adds a query parameter to the URI query if the parameter value is not <jk>null</jk> or an empty string.
297    *
298    * <p>
299    * NE = "not empty"
300    *
301    * @param name The parameter name.
302    * @param value The parameter value converted to a string using UON notation.
303    * @return This object (for method chaining).
304    * @throws RestCallException Invalid input.
305    */
306   public RestCall queryIfNE(String name, Object value) throws RestCallException {
307      return query(name, value, true, null, null);
308   }
309
310   /**
311    * Adds query parameters to the URI for any parameters that aren't null/empty.
312    *
313    * <p>
314    * NE = "not empty"
315    *
316    * @param params The parameters.  Values are converted to a string using UON notation.
317    * @return This object (for method chaining).
318    * @throws RestCallException Invalid input.
319    */
320   public RestCall queryIfNE(Map<String,Object> params) throws RestCallException {
321      return query(null, params, true, null, null);
322   }
323
324   /**
325    * Sets a custom URI query.
326    *
327    * @param query The new URI query string.
328    * @return This object (for method chaining).
329    */
330   public RestCall query(String query) {
331      uriBuilder.setCustomQuery(query);
332      return this;
333   }
334
335   /**
336    * Adds a form data pair to this request to perform a URL-encoded form post.
337    *
338    * @param name
339    *    The parameter name.
340    *    Can be null/blank/* if the value is a {@link Map}, {@link NameValuePairs}, or bean.
341    * @param value
342    *    The parameter value converted to a string using UON notation.
343    *    Can also be {@link Map}, {@link NameValuePairs}, or bean if the name is null/blank/*.
344    * @param skipIfEmpty Don't add the pair if the value is empty.
345    * @param serializer
346    *    The serializer to use for serializing the value to a string value.
347    *    If <jk>null</jk>, then the URL-encoding serializer defined on the client is used.
348    * @param schema
349    *    The schema object that defines the format of the output.
350    *    <br>If <jk>null</jk>, defaults to the schema defined on the serializer.
351    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
352    *    <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}).
353    * @return This object (for method chaining).
354    * @throws RestCallException Invalid input.
355    */
356   public RestCall formData(String name, Object value, boolean skipIfEmpty, HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
357      if (formData == null)
358         formData = new NameValuePairs();
359      if (serializer == null)
360         serializer = client.getPartSerializer();
361      if (schema == null)
362         schema = HttpPartSchema.DEFAULT;
363      boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairs;
364      if (! isMulti) {
365         if (canAdd(value, schema, skipIfEmpty))
366            formData.add(new SerializedNameValuePair(name, value, serializer, schema));
367      } else if (value instanceof NameValuePairs) {
368         for (NameValuePair p : (NameValuePairs)value) {
369            String n = p.getName();
370            String v = p.getValue();
371            HttpPartSchema s = schema.getProperty(n);
372            if (canAdd(v, s, skipIfEmpty))
373               formData.add(p);
374         }
375      } else if (value instanceof Map) {
376         for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet()) {
377            String n = p.getKey();
378            Object v = p.getValue();
379            HttpPartSchema s = schema.getProperty(n);
380            if (canAdd(v, s, skipIfEmpty))
381               formData(n, v, skipIfEmpty, serializer, s);
382         }
383      } else if (isBean(value)) {
384         return formData(name, toBeanMap(value), skipIfEmpty, serializer, schema);
385      } else if (value instanceof Reader || value instanceof InputStream) {
386         contentType("application/x-www-form-urlencoded");
387         body(value);
388      } else if (value instanceof CharSequence) {
389         try {
390            contentType("application/x-www-form-urlencoded");
391            body(new StringEntity(value.toString()));
392         } catch (UnsupportedEncodingException e) {}
393      } else {
394         throw new FormattedRuntimeException("Invalid name ''{0}'' passed to formData(name,value,skipIfEmpty) for data type ''{1}''", name, className(value));
395      }
396      return this;
397   }
398
399   /**
400    * Adds a form data pair to this request to perform a URL-encoded form post.
401    *
402    * @param name
403    *    The parameter name.
404    *    Can be null/blank if the value is a {@link Map} or {@link NameValuePairs}.
405    * @param value
406    *    The parameter value converted to a string using UON notation.
407    *    Can also be a {@link Map} or {@link NameValuePairs}.
408    * @return This object (for method chaining).
409    * @throws RestCallException If name was null/blank and value wasn't a {@link Map} or {@link NameValuePairs}.
410    */
411   public RestCall formData(String name, Object value) throws RestCallException {
412      return formData(name, value, false, null, null);
413   }
414
415   /**
416    * Adds form data pairs to this request to perform a URL-encoded form post.
417    *
418    * @param nameValuePairs The name-value pairs of the request.
419    * @return This object (for method chaining).
420    * @throws RestCallException Invalid input.
421    */
422   public RestCall formData(NameValuePairs nameValuePairs) throws RestCallException {
423      return formData(null, nameValuePairs);
424   }
425
426   /**
427    * Adds form data pairs to this request to perform a URL-encoded form post.
428    *
429    * @param params The parameters.  Values are converted to a string using UON notation.
430    * @return This object (for method chaining).
431    * @throws RestCallException If name was null/blank and value wasn't a {@link Map} or {@link NameValuePairs}.
432    */
433   public RestCall formData(Map<String,Object> params) throws RestCallException {
434      return formData(null, params);
435   }
436
437   /**
438    * Adds a form data pair to the request if the parameter value is not <jk>null</jk> or an empty string.
439    *
440    * <p>
441    * NE = "not empty"
442    *
443    * @param name The parameter name.
444    * @param value The parameter value converted to a string using UON notation.
445    * @return This object (for method chaining).
446    * @throws RestCallException Invalid input.
447    */
448   public RestCall formDataIfNE(String name, Object value) throws RestCallException {
449      return formData(name, value, true, null, null);
450   }
451
452   /**
453    * Adds form data parameters to the request for any parameters that aren't null/empty.
454    *
455    * <p>
456    * NE = "not empty"
457    *
458    * @param params The parameters.  Values are converted to a string using UON notation.
459    * @return This object (for method chaining).
460    * @throws RestCallException Invalid input.
461    */
462   public RestCall formDataIfNE(Map<String,Object> params) throws RestCallException {
463      return formData(null, params, true, null, null);
464   }
465
466   /**
467    * Replaces a variable of the form <js>"{name}"</js> in the URL path with the specified value.
468    *
469    * @param name The path variable name.
470    * @param value The replacement value.
471    * @param serializer
472    *    The serializer to use for serializing the value to a string value.
473    *    If <jk>null</jk>, then the URL-encoding serializer defined on the client is used.
474    * @param schema
475    *    The schema object that defines the format of the output.
476    *    <br>If <jk>null</jk>, defaults to the schema defined on the serializer.
477    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
478    *    <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}).
479    * @return This object (for method chaining).
480    * @throws RestCallException If variable could not be found in path.
481    */
482   public RestCall path(String name, Object value, HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
483      String path = uriBuilder.getPath();
484      if (serializer == null)
485         serializer = client.getPartSerializer();
486      if (schema == null)
487         schema = HttpPartSchema.DEFAULT;
488      boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairs;
489      if (! isMulti) {
490         String var = "{" + name + "}";
491         if (path.indexOf(var) == -1 && ! name.equals("/*"))
492            throw new RestCallException("Path variable {"+name+"} was not found in path.");
493         try {
494            String p = null;
495            if (name.equals("/*"))
496               p = path.replaceAll("\\/\\*$", serializer.serialize(PATH, schema, value));
497            else
498               p = path.replace(var, serializer.serialize(PATH, schema, value));
499            uriBuilder.setPath(p);
500         } catch (SchemaValidationException e) {
501            throw new RestCallException(e, "Validation error on request path parameter ''{0}''=''{1}''", name, value);
502         } catch (SerializeException e) {
503            throw new RestCallException(e, "Serialization error on request path parameter ''{0}''", name);
504         }
505      } else if (value instanceof NameValuePairs) {
506         for (NameValuePair p : (NameValuePairs)value) {
507            String n = p.getName();
508            String v = p.getValue();
509            HttpPartSchema s = schema.getProperty(n);
510            path(n, v, serializer, s);
511         }
512      } else if (value instanceof Map) {
513         for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet()) {
514            String n = p.getKey();
515            Object v = p.getValue();
516            HttpPartSchema s = schema.getProperty(n);
517            path(n, v, serializer, s);
518         }
519      } else if (isBean(value)) {
520         return path(name, toBeanMap(value), serializer, schema);
521      } else if (value != null) {
522         throw new RestCallException("Invalid name ''{0}'' passed to path(name,value) for data type ''{1}''", name, className(value));
523      }
524      return this;
525   }
526
527   /**
528    * Replaces a variable of the form <js>"{name}"</js> in the URL path with the specified value.
529    *
530    * @param name The path variable name.
531    * @param value The replacement value.
532    * @return This object (for method chaining).
533    * @throws RestCallException If variable could not be found in path.
534    */
535   public RestCall path(String name, Object value) throws RestCallException {
536      return path(name, value, null, null);
537   }
538
539   /**
540    * Sets the URI user info.
541    *
542    * @param userInfo The new URI user info.
543    * @return This object (for method chaining).
544    */
545   public RestCall userInfo(String userInfo) {
546      uriBuilder.setUserInfo(userInfo);
547      return this;
548   }
549
550   /**
551    * Sets the URI user info.
552    *
553    * @param username The new URI username.
554    * @param password The new URI password.
555    * @return This object (for method chaining).
556    */
557   public RestCall userInfo(String username, String password) {
558      uriBuilder.setUserInfo(username, password);
559      return this;
560   }
561
562   /**
563    * Specifies the part schema for the request body.
564    *
565    * <p>
566    * This is only useful for schema-aware serializers such as {@link OpenApiSerializer}.
567    *
568    * @param value
569    *    The new part schema for the request body.
570    *    <br>Can be <jk>null</jk>.
571    * @return This object (for method chaining).
572    */
573   public RestCall requestBodySchema(HttpPartSchema value) {
574      this.requestBodySchema = value;
575      return this;
576   }
577
578   /**
579    * Specifies the part schema for the response body.
580    *
581    * <p>
582    * This is only useful for schema-aware parsers such as {@link OpenApiParser}.
583    *
584    * @param value
585    *    The new part schema for the response body.
586    *    <br>Can be <jk>null</jk>.
587    * @return This object (for method chaining).
588    */
589   public RestCall responseBodySchema(HttpPartSchema value) {
590      this.responseBodySchema = value;
591      return this;
592   }
593
594   /**
595    * Sets the input for this REST call.
596    *
597    * @param input
598    *    The input to be sent to the REST resource (only valid for PUT and POST) requests.
599    *    <br>Can be of the following types:
600    *    <ul class='spaced-list'>
601    *       <li>
602    *          {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
603    *       <li>
604    *          {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
605    *       <li>
606    *          {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the
607    *          {@link RestClient}.
608    *       <li>
609    *          {@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
610    *       <li>
611    *          {@link NameValuePairs} - Converted to a URL-encoded FORM post.
612    *    </ul>
613    * @return This object (for method chaining).
614    * @throws RestCallException If a retry was attempted, but the entity was not repeatable.
615    */
616   public RestCall body(Object input) throws RestCallException {
617      this.input = input;
618      this.hasInput = true;
619      this.formData = null;
620      return this;
621   }
622
623   /**
624    * Specifies the serializer to use on this call.
625    *
626    * <p>
627    * Overrides the serializer specified on the {@link RestClient}.
628    *
629    * @param serializer The serializer used to serialize POJOs to the body of the HTTP request.
630    * @return This object (for method chaining).
631    */
632   public RestCall serializer(Serializer serializer) {
633      this.serializer = serializer;
634      return this;
635   }
636
637   /**
638    * Specifies the parser to use on this call.
639    *
640    * <p>
641    * Overrides the parser specified on the {@link RestClient}.
642    *
643    * @param parser The parser used to parse POJOs from the body of the HTTP response.
644    * @return This object (for method chaining).
645    */
646   public RestCall parser(Parser parser) {
647      this.parser = parser;
648      return this;
649   }
650
651   //-----------------------------------------------------------------------------------------------------------------
652   // HTTP headers
653   //-----------------------------------------------------------------------------------------------------------------
654
655   /**
656    * Sets a header on the request.
657    *
658    * @param name
659    *    The header name.
660    *    The name can be null/empty if the value is a {@link Map}.
661    * @param value The header value.
662    * @param skipIfEmpty Don't add the header if the name is null/empty.
663    * @param serializer
664    *    The serializer to use for serializing the value to a string value.
665    *    If <jk>null</jk>, then the URL-encoding serializer defined on the client is used.
666    * @param schema
667    *    The schema object that defines the format of the output.
668    *    <br>If <jk>null</jk>, defaults to the schema defined on the serializer.
669    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
670    *    <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}).
671    * @return This object (for method chaining).
672    * @throws RestCallException Invalid input.
673    */
674   public RestCall header(String name, Object value, boolean skipIfEmpty, HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
675      if (serializer == null)
676         serializer = client.getPartSerializer();
677      if (schema == null)
678         schema = HttpPartSchema.DEFAULT;
679      boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairs;
680      if (! isMulti) {
681         if (canAdd(value, schema, skipIfEmpty))
682            try {
683               request.setHeader(name, serializer.serialize(HEADER, schema, value));
684            } catch (SchemaValidationException e) {
685               throw new RestCallException(e, "Validation error on request header parameter ''{0}''=''{1}''", name, value);
686            } catch (SerializeException e) {
687               throw new RestCallException(e, "Serialization error on request header parameter ''{0}''", name);
688            }
689      } else if (value instanceof NameValuePairs) {
690         for (NameValuePair p : (NameValuePairs)value) {
691            String n = p.getName();
692            String v = p.getValue();
693            HttpPartSchema s = schema.getProperty(n);
694            if (canAdd(v, s, skipIfEmpty))
695               header(n, v, skipIfEmpty, serializer, s);
696         }
697      } else if (value instanceof Map) {
698         for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet()) {
699            String n = p.getKey();
700            Object v = p.getValue();
701            HttpPartSchema s = schema.getProperty(n);
702            if (canAdd(v, s, skipIfEmpty))
703               header(n, v, skipIfEmpty, serializer, s);
704         }
705      } else if (isBean(value)) {
706         return header(name, toBeanMap(value), skipIfEmpty, serializer, schema);
707      } else {
708         throw new RestCallException("Invalid name ''{0}'' passed to header(name,value,skipIfEmpty) for data type ''{1}''", name, className(value));
709      }
710      return this;
711   }
712
713
714   /**
715    * Sets a header on the request.
716    *
717    * @param name
718    *    The header name.
719    *    The name can be null/empty if the value is a {@link Map}.
720    * @param value The header value.
721    * @return This object (for method chaining).
722    * @throws RestCallException Invalid input.
723    */
724   public RestCall header(String name, Object value) throws RestCallException {
725      return header(name, value, false, null, null);
726   }
727
728   /**
729    * Sets headers on the request.
730    *
731    * @param values The header values.
732    * @return This object (for method chaining).
733    * @throws RestCallException Invalid input.
734    */
735   public RestCall headers(Map<String,Object> values) throws RestCallException {
736      return header(null, values, false, null, null);
737   }
738
739   /**
740    * Sets a header on the request if the value is not null/empty.
741    *
742    * <p>
743    * NE = "not empty"
744    *
745    * @param name
746    *    The header name.
747    *    The name can be null/empty if the value is a {@link Map}.
748    * @param value The header value.
749    * @return This object (for method chaining).
750    * @throws RestCallException Invalid input.
751    */
752   public RestCall headerIfNE(String name, Object value) throws RestCallException {
753      return header(name, value, true, null, null);
754   }
755
756   /**
757    * Sets headers on the request if the values are not null/empty.
758    *
759    * <p>
760    * NE = "not empty"
761    *
762    * @param values The header values.
763    * @return This object (for method chaining).
764    * @throws RestCallException Invalid input.
765    */
766   public RestCall headersIfNE(Map<String,Object> values) throws RestCallException {
767      return header(null, values, true, null, null);
768   }
769
770   /**
771    * Sets the value for the <c>Accept</c> request header.
772    *
773    * <p>
774    * This overrides the media type specified on the parser, but is overridden by calling
775    * <code>header(<js>"Accept"</js>, value);</code>
776    *
777    * @param value The new header value.
778    * @return This object (for method chaining).
779    * @throws RestCallException Invalid input.
780    */
781   public RestCall accept(Object value) throws RestCallException {
782      return header("Accept", value);
783   }
784
785   /**
786    * Sets the value for the <c>Accept-Charset</c> request header.
787    *
788    * <p>
789    * This is a shortcut for calling <code>header(<js>"Accept-Charset"</js>, value);</code>
790    *
791    * @param value The new header value.
792    * @return This object (for method chaining).
793    * @throws RestCallException Invalid input.
794    */
795   public RestCall acceptCharset(Object value) throws RestCallException {
796      return header("Accept-Charset", value);
797   }
798
799   /**
800    * Sets the value for the <c>Accept-Encoding</c> request header.
801    *
802    * <p>
803    * This is a shortcut for calling <code>header(<js>"Accept-Encoding"</js>, value);</code>
804    *
805    * @param value The new header value.
806    * @return This object (for method chaining).
807    * @throws RestCallException Invalid input.
808    */
809   public RestCall acceptEncoding(Object value) throws RestCallException {
810      return header("Accept-Encoding", value);
811   }
812
813   /**
814    * Sets the value for the <c>Accept-Language</c> request header.
815    *
816    * <p>
817    * This is a shortcut for calling <code>header(<js>"Accept-Language"</js>, value);</code>
818    *
819    * @param value The new header value.
820    * @return This object (for method chaining).
821    * @throws RestCallException Invalid input.
822    */
823   public RestCall acceptLanguage(Object value) throws RestCallException {
824      return header("Accept-Language", value);
825   }
826
827   /**
828    * Sets the value for the <c>Authorization</c> request header.
829    *
830    * <p>
831    * This is a shortcut for calling <code>header(<js>"Authorization"</js>, value);</code>
832    *
833    * @param value The new header value.
834    * @return This object (for method chaining).
835    * @throws RestCallException Invalid input.
836    */
837   public RestCall authorization(Object value) throws RestCallException {
838      return header("Authorization", value);
839   }
840
841   /**
842    * Sets the value for the <c>Cache-Control</c> request header.
843    *
844    * <p>
845    * This is a shortcut for calling <code>header(<js>"Cache-Control"</js>, value);</code>
846    *
847    * @param value The new header value.
848    * @return This object (for method chaining).
849    * @throws RestCallException Invalid input.
850    */
851   public RestCall cacheControl(Object value) throws RestCallException {
852      return header("Cache-Control", value);
853   }
854
855   /**
856    * Sets the value for the <c>Connection</c> request header.
857    *
858    * <p>
859    * This is a shortcut for calling <code>header(<js>"Connection"</js>, value);</code>
860    *
861    * @param value The new header value.
862    * @return This object (for method chaining).
863    * @throws RestCallException Invalid input.
864    */
865   public RestCall connection(Object value) throws RestCallException {
866      return header("Connection", value);
867   }
868
869   /**
870    * Sets the value for the <c>Content-Length</c> request header.
871    *
872    * <p>
873    * This is a shortcut for calling <code>header(<js>"Content-Length"</js>, value);</code>
874    *
875    * @param value The new header value.
876    * @return This object (for method chaining).
877    * @throws RestCallException Invalid input.
878    */
879   public RestCall contentLength(Object value) throws RestCallException {
880      return header("Content-Length", value);
881   }
882
883   /**
884    * Sets the value for the <c>Content-Type</c> request header.
885    *
886    * <p>
887    * This overrides the media type specified on the serializer, but is overridden by calling
888    * <code>header(<js>"Content-Type"</js>, value);</code>
889    *
890    * @param value The new header value.
891    * @return This object (for method chaining).
892    * @throws RestCallException Invalid input.
893    */
894   public RestCall contentType(Object value) throws RestCallException {
895      return header("Content-Type", value);
896   }
897
898   /**
899    * Sets the value for the <c>Date</c> request header.
900    *
901    * <p>
902    * This is a shortcut for calling <code>header(<js>"Date"</js>, value);</code>
903    *
904    * @param value The new header value.
905    * @return This object (for method chaining).
906    * @throws RestCallException Invalid input.
907    */
908   public RestCall date(Object value) throws RestCallException {
909      return header("Date", value);
910   }
911
912   /**
913    * Sets the value for the <c>Expect</c> request header.
914    *
915    * <p>
916    * This is a shortcut for calling <code>header(<js>"Expect"</js>, value);</code>
917    *
918    * @param value The new header value.
919    * @return This object (for method chaining).
920    * @throws RestCallException Invalid input.
921    */
922   public RestCall expect(Object value) throws RestCallException {
923      return header("Expect", value);
924   }
925
926   /**
927    * Sets the value for the <c>Forwarded</c> request header.
928    *
929    * <p>
930    * This is a shortcut for calling <code>header(<js>"Forwarded"</js>, value);</code>
931    *
932    * @param value The new header value.
933    * @return This object (for method chaining).
934    * @throws RestCallException Invalid input.
935    */
936   public RestCall forwarded(Object value) throws RestCallException {
937      return header("Forwarded", value);
938   }
939
940   /**
941    * Sets the value for the <c>From</c> request header.
942    *
943    * <p>
944    * This is a shortcut for calling <code>header(<js>"From"</js>, value);</code>
945    *
946    * @param value The new header value.
947    * @return This object (for method chaining).
948    * @throws RestCallException Invalid input.
949    */
950   public RestCall from(Object value) throws RestCallException {
951      return header("From", value);
952   }
953
954   /**
955    * Sets the value for the <c>Host</c> request header.
956    *
957    * <p>
958    * This is a shortcut for calling <code>header(<js>"Host"</js>, value);</code>
959    *
960    * @param value The new header value.
961    * @return This object (for method chaining).
962    * @throws RestCallException Invalid input.
963    */
964   public RestCall host(Object value) throws RestCallException {
965      return header("Host", value);
966   }
967
968   /**
969    * Sets the value for the <c>If-Match</c> request header.
970    *
971    * <p>
972    * This is a shortcut for calling <code>header(<js>"If-Match"</js>, value);</code>
973    *
974    * @param value The new header value.
975    * @return This object (for method chaining).
976    * @throws RestCallException Invalid input.
977    */
978   public RestCall ifMatch(Object value) throws RestCallException {
979      return header("If-Match", value);
980   }
981
982   /**
983    * Sets the value for the <c>If-Modified-Since</c> request header.
984    *
985    * <p>
986    * This is a shortcut for calling <code>header(<js>"If-Modified-Since"</js>, value);</code>
987    *
988    * @param value The new header value.
989    * @return This object (for method chaining).
990    * @throws RestCallException Invalid input.
991    */
992   public RestCall ifModifiedSince(Object value) throws RestCallException {
993      return header("If-Modified-Since", value);
994   }
995
996   /**
997    * Sets the value for the <c>If-None-Match</c> request header.
998    *
999    * <p>
1000    * This is a shortcut for calling <code>header(<js>"If-None-Match"</js>, value);</code>
1001    *
1002    * @param value The new header value.
1003    * @return This object (for method chaining).
1004    * @throws RestCallException Invalid input.
1005    */
1006   public RestCall ifNoneMatch(Object value) throws RestCallException {
1007      return header("If-None-Match", value);
1008   }
1009
1010   /**
1011    * Sets the value for the <c>If-Range</c> request header.
1012    *
1013    * <p>
1014    * This is a shortcut for calling <code>header(<js>"If-Range"</js>, value);</code>
1015    *
1016    * @param value The new header value.
1017    * @return This object (for method chaining).
1018    * @throws RestCallException Invalid input.
1019    */
1020   public RestCall ifRange(Object value) throws RestCallException {
1021      return header("If-Range", value);
1022   }
1023
1024   /**
1025    * Sets the value for the <c>If-Unmodified-Since</c> request header.
1026    *
1027    * <p>
1028    * This is a shortcut for calling <code>header(<js>"If-Unmodified-Since"</js>, value);</code>
1029    *
1030    * @param value The new header value.
1031    * @return This object (for method chaining).
1032    * @throws RestCallException Invalid input.
1033    */
1034   public RestCall ifUnmodifiedSince(Object value) throws RestCallException {
1035      return header("If-Unmodified-Since", value);
1036   }
1037
1038   /**
1039    * Sets the value for the <c>Max-Forwards</c> request header.
1040    *
1041    * <p>
1042    * This is a shortcut for calling <code>header(<js>"Max-Forwards"</js>, value);</code>
1043    *
1044    * @param value The new header value.
1045    * @return This object (for method chaining).
1046    * @throws RestCallException Invalid input.
1047    */
1048   public RestCall maxForwards(Object value) throws RestCallException {
1049      return header("Max-Forwards", value);
1050   }
1051
1052   /**
1053    * Sets the value for the <c>Origin</c> request header.
1054    *
1055    * <p>
1056    * This is a shortcut for calling <code>header(<js>"Origin"</js>, value);</code>
1057    *
1058    * @param value The new header value.
1059    * @return This object (for method chaining).
1060    * @throws RestCallException Invalid input.
1061    */
1062   public RestCall origin(Object value) throws RestCallException {
1063      return header("Origin", value);
1064   }
1065
1066   /**
1067    * Sets the value for the <c>Pragma</c> request header.
1068    *
1069    * <p>
1070    * This is a shortcut for calling <code>header(<js>"Pragma"</js>, value);</code>
1071    *
1072    * @param value The new header value.
1073    * @return This object (for method chaining).
1074    * @throws RestCallException Invalid input.
1075    */
1076   public RestCall pragma(Object value) throws RestCallException {
1077      return header("Pragma", value);
1078   }
1079
1080   /**
1081    * Sets the value for the <c>Proxy-Authorization</c> request header.
1082    *
1083    * <p>
1084    * This is a shortcut for calling <code>header(<js>"Proxy-Authorization"</js>, value);</code>
1085    *
1086    * @param value The new header value.
1087    * @return This object (for method chaining).
1088    * @throws RestCallException Invalid input.
1089    */
1090   public RestCall proxyAuthorization(Object value) throws RestCallException {
1091      return header("Proxy-Authorization", value);
1092   }
1093
1094   /**
1095    * Sets the value for the <c>Range</c> request header.
1096    *
1097    * <p>
1098    * This is a shortcut for calling <code>header(<js>"Range"</js>, value);</code>
1099    *
1100    * @param value The new header value.
1101    * @return This object (for method chaining).
1102    * @throws RestCallException Invalid input.
1103    */
1104   public RestCall range(Object value) throws RestCallException {
1105      return header("Range", value);
1106   }
1107
1108   /**
1109    * Sets the value for the <c>Referer</c> request header.
1110    *
1111    * <p>
1112    * This is a shortcut for calling <code>header(<js>"Referer"</js>, value);</code>
1113    *
1114    * @param value The new header value.
1115    * @return This object (for method chaining).
1116    * @throws RestCallException Invalid input.
1117    */
1118   public RestCall referer(Object value) throws RestCallException {
1119      return header("Referer", value);
1120   }
1121
1122   /**
1123    * Sets the value for the <c>TE</c> request header.
1124    *
1125    * <p>
1126    * This is a shortcut for calling <code>header(<js>"TE"</js>, value);</code>
1127    *
1128    * @param value The new header value.
1129    * @return This object (for method chaining).
1130    * @throws RestCallException Invalid input.
1131    */
1132   public RestCall te(Object value) throws RestCallException {
1133      return header("TE", value);
1134   }
1135
1136   /**
1137    * Sets the value for the <c>User-Agent</c> request header.
1138    *
1139    * <p>
1140    * This is a shortcut for calling <code>header(<js>"User-Agent"</js>, value);</code>
1141    *
1142    * @param value The new header value.
1143    * @return This object (for method chaining).
1144    * @throws RestCallException Invalid input.
1145    */
1146   public RestCall userAgent(Object value) throws RestCallException {
1147      return header("User-Agent", value);
1148   }
1149
1150   /**
1151    * Sets the value for the <c>Upgrade</c> request header.
1152    *
1153    * <p>
1154    * This is a shortcut for calling <code>header(<js>"Upgrade"</js>, value);</code>
1155    *
1156    * @param value The new header value.
1157    * @return This object (for method chaining).
1158    * @throws RestCallException Invalid input.
1159    */
1160   public RestCall upgrade(Object value) throws RestCallException {
1161      return header("Upgrade", value);
1162   }
1163
1164   /**
1165    * Sets the value for the <c>Via</c> request header.
1166    *
1167    * <p>
1168    * This is a shortcut for calling <code>header(<js>"Via"</js>, value);</code>
1169    *
1170    * @param value The new header value.
1171    * @return This object (for method chaining).
1172    * @throws RestCallException Invalid input.
1173    */
1174   public RestCall via(Object value) throws RestCallException {
1175      return header("Via", value);
1176   }
1177
1178   /**
1179    * Sets the value for the <c>Warning</c> request header.
1180    *
1181    * <p>
1182    * This is a shortcut for calling <code>header(<js>"Warning"</js>, value);</code>
1183    *
1184    * @param value The new header value.
1185    * @return This object (for method chaining).
1186    * @throws RestCallException Invalid input.
1187    */
1188   public RestCall warning(Object value) throws RestCallException {
1189      return header("Warning", value);
1190   }
1191
1192   /**
1193    * Sets the client version by setting the value for the <js>"X-Client-Version"</js> header.
1194    *
1195    * @param version The version string (e.g. <js>"1.2.3"</js>)
1196    * @return This object (for method chaining).
1197    * @throws RestCallException Invalid input.
1198    */
1199   public RestCall clientVersion(String version) throws RestCallException {
1200      return header("X-Client-Version", version);
1201   }
1202
1203   /**
1204    * Make this call retryable if an error response (>=400) is received.
1205    *
1206    * @param retries The number of retries to attempt.
1207    * @param interval The time in milliseconds between attempts.
1208    * @param retryOn
1209    *    Optional object used for determining whether a retry should be attempted.
1210    *    If <jk>null</jk>, uses {@link RetryOn#DEFAULT}.
1211    * @return This object (for method chaining).
1212    * @throws RestCallException If current entity is not repeatable.
1213    */
1214   public RestCall retryable(int retries, long interval, RetryOn retryOn) throws RestCallException {
1215      if (request instanceof HttpEntityEnclosingRequestBase) {
1216         if (input != null && input instanceof HttpEntity) {
1217            HttpEntity e = (HttpEntity)input;
1218            if (e != null && ! e.isRepeatable())
1219               throw new RestCallException("Attempt to make call retryable, but entity is not repeatable.");
1220            }
1221         }
1222      this.retries = retries;
1223      this.retryInterval = interval;
1224      this.retryOn = (retryOn == null ? RetryOn.DEFAULT : retryOn);
1225      return this;
1226
1227   }
1228
1229   /**
1230    * For this call, allow automatic redirects when a 302 or 307 occurs when performing a POST.
1231    *
1232    * <p>
1233    * Note that this can be inefficient since the POST body needs to be serialized twice.
1234    * The preferred approach if possible is to use the {@link LaxRedirectStrategy} strategy on the underlying HTTP
1235    * client.
1236    * However, this method is provided if you don't have access to the underlying client.
1237    *
1238    * @param b Redirect flag.
1239    * @return This object (for method chaining).
1240    */
1241   public RestCall allowRedirectsOnPosts(boolean b) {
1242      this.allowRedirectsOnPosts = b;
1243      return this;
1244   }
1245
1246   /**
1247    * Specify the number of redirects to follow before throwing an exception.
1248    *
1249    * @param maxAttempts Allow a redirect to occur this number of times.
1250    * @return This object (for method chaining).
1251    */
1252   public RestCall redirectMaxAttempts(int maxAttempts) {
1253      this.redirectOnPostsTries = maxAttempts;
1254      return this;
1255   }
1256
1257   /**
1258    * Add an interceptor for this call only.
1259    *
1260    * @param interceptor The interceptor to add to this call.
1261    * @return This object (for method chaining).
1262    */
1263   public RestCall interceptor(RestCallInterceptor interceptor) {
1264      interceptors.add(interceptor);
1265      interceptor.onInit(this);
1266      return this;
1267   }
1268
1269   /**
1270    * Pipes the request output to the specified writer when {@link #run()} is called.
1271    *
1272    * <p>
1273    * The writer is not closed.
1274    *
1275    * <p>
1276    * This method can be called multiple times to pipe to multiple writers.
1277    *
1278    * @param w The writer to pipe the output to.
1279    * @return This object (for method chaining).
1280    */
1281   public RestCall pipeTo(Writer w) {
1282      return pipeTo(w, false);
1283   }
1284
1285   /**
1286    * Pipe output from response to the specified writer when {@link #run()} is called.
1287    *
1288    * <p>
1289    * This method can be called multiple times to pipe to multiple writers.
1290    *
1291    * @param w The writer to write the output to.
1292    * @param close Close the writer when {@link #close()} is called.
1293    * @return This object (for method chaining).
1294    */
1295   public RestCall pipeTo(Writer w, boolean close) {
1296      return pipeTo(null, w, close);
1297   }
1298
1299   /**
1300    * Pipe output from response to the specified writer when {@link #run()} is called and associate that writer with an
1301    * ID so it can be retrieved through {@link #getWriter(String)}.
1302    *
1303    * <p>
1304    * This method can be called multiple times to pipe to multiple writers.
1305    *
1306    * @param id A string identifier that can be used to retrieve the writer using {@link #getWriter(String)}
1307    * @param w The writer to write the output to.
1308    * @param close Close the writer when {@link #close()} is called.
1309    * @return This object (for method chaining).
1310    */
1311   public RestCall pipeTo(String id, Writer w, boolean close) {
1312      writers.add(id, w, close);
1313      return this;
1314   }
1315
1316   /**
1317    * Retrieves a writer associated with an ID via {@link #pipeTo(String, Writer, boolean)}
1318    *
1319    * @param id A string identifier that can be used to retrieve the writer using {@link #getWriter(String)}
1320    * @return The writer, or <jk>null</jk> if no writer is associated with that ID.
1321    */
1322   public Writer getWriter(String id) {
1323      return writers.getWriter(id);
1324   }
1325
1326   /**
1327    * When output is piped to writers, flush the writers after every line of output.
1328    *
1329    * @return This object (for method chaining).
1330    */
1331   public RestCall byLines() {
1332      this.byLines = true;
1333      return this;
1334   }
1335
1336   /**
1337    * Pipes the request output to the specified output stream when {@link #run()} is called.
1338    *
1339    * <p>
1340    * The output stream is not closed.
1341    *
1342    * <p>
1343    * This method can be called multiple times to pipe to multiple output streams.
1344    *
1345    * @param os The output stream to pipe the output to.
1346    * @return This object (for method chaining).
1347    */
1348   public RestCall pipeTo(OutputStream os) {
1349      return pipeTo(os, false);
1350   }
1351
1352   /**
1353    * Pipe output from response to the specified output stream when {@link #run()} is called.
1354    *
1355    * <p>
1356    * This method can be called multiple times to pipe to multiple output stream.
1357    *
1358    * @param os The output stream to write the output to.
1359    * @param close Close the output stream when {@link #close()} is called.
1360    * @return This object (for method chaining).
1361    */
1362   public RestCall pipeTo(OutputStream os, boolean close) {
1363      return pipeTo(null, os, close);
1364   }
1365
1366   /**
1367    * Pipe output from response to the specified output stream when {@link #run()} is called and associate
1368    * that output stream with an ID so it can be retrieved through {@link #getOutputStream(String)}.
1369    *
1370    * <p>
1371    * This method can be called multiple times to pipe to multiple output stream.
1372    *
1373    * @param id A string identifier that can be used to retrieve the output stream using {@link #getOutputStream(String)}
1374    * @param os The output stream to write the output to.
1375    * @param close Close the output stream when {@link #close()} is called.
1376    * @return This object (for method chaining).
1377    */
1378   public RestCall pipeTo(String id, OutputStream os, boolean close) {
1379      outputStreams.add(id, os, close);
1380      return this;
1381   }
1382
1383   /**
1384    * Retrieves an output stream associated with an ID via {@link #pipeTo(String, OutputStream, boolean)}
1385    *
1386    * @param id A string identifier that can be used to retrieve the writer using {@link #getWriter(String)}
1387    * @return The writer, or <jk>null</jk> if no writer is associated with that ID.
1388    */
1389   public OutputStream getOutputStream(String id) {
1390      return outputStreams.getOutputStream(id);
1391   }
1392
1393   /**
1394    * Prevent {@link RestCallException RestCallExceptions} from being thrown when HTTP status 400+ is encountered.
1395    *
1396    * @return This object (for method chaining).
1397    */
1398   public RestCall ignoreErrors() {
1399      this.ignoreErrors = true;
1400      return this;
1401   }
1402
1403   /**
1404    * Stores the response text so that it can later be captured using {@link #getCapturedResponse()}.
1405    *
1406    * <p>
1407    * This method should only be called once.  Multiple calls to this method are ignored.
1408    *
1409    * @return This object (for method chaining).
1410    */
1411   public RestCall captureResponse() {
1412      if (capturedResponseWriter == null) {
1413         capturedResponseWriter = new StringWriter();
1414         writers.add(capturedResponseWriter, false);
1415      }
1416      return this;
1417   }
1418
1419
1420   /**
1421    * Look for the specified regular expression pattern in the response output.
1422    *
1423    * <p>
1424    * Causes a {@link RestCallException} to be thrown if the specified pattern is found in the output.
1425    *
1426    * <p>
1427    * This method uses {@link #getCapturedResponse()} to read the response text and so does not affect the other output
1428    * methods such as {@link #getResponseAsString()}.
1429    *
1430    * <h5 class='section'>Example:</h5>
1431    * <p class='bcode w800'>
1432    *    <jc>// Throw a RestCallException if FAILURE or ERROR is found in the output.</jc>
1433    *    restClient.doGet(<jsf>URL</jsf>)
1434    *       .failurePattern(<js>"FAILURE|ERROR"</js>)
1435    *       .run();
1436    * </p>
1437    *
1438    * @param errorPattern A regular expression to look for in the response output.
1439    * @return This object (for method chaining).
1440    */
1441   public RestCall failurePattern(final String errorPattern) {
1442      responsePattern(
1443         new ResponsePattern(errorPattern) {
1444            @Override
1445            public void onMatch(RestCall rc, Matcher m) throws RestCallException {
1446               throw new RestCallException("Failure pattern detected.");
1447            }
1448         }
1449      );
1450      return this;
1451   }
1452
1453   /**
1454    * Look for the specified regular expression pattern in the response output.
1455    *
1456    * <p>
1457    * Causes a {@link RestCallException} to be thrown if the specified pattern is not found in the output.
1458    *
1459    * <p>
1460    * This method uses {@link #getCapturedResponse()} to read the response text and so does not affect the other output
1461    * methods such as {@link #getResponseAsString()}.
1462    *
1463    * <h5 class='section'>Example:</h5>
1464    * <p class='bcode w800'>
1465    *    <jc>// Throw a RestCallException if SUCCESS is not found in the output.</jc>
1466    *    restClient.doGet(<jsf>URL</jsf>)
1467    *       .successPattern(<js>"SUCCESS"</js>)
1468    *       .run();
1469    * </p>
1470    *
1471    * @param successPattern A regular expression to look for in the response output.
1472    * @return This object (for method chaining).
1473    */
1474   public RestCall successPattern(String successPattern) {
1475      responsePattern(
1476         new ResponsePattern(successPattern) {
1477            @Override
1478            public void onNoMatch(RestCall rc) throws RestCallException {
1479               throw new RestCallException("Success pattern not detected.");
1480            }
1481         }
1482      );
1483      return this;
1484   }
1485
1486   /**
1487    * Adds a response pattern finder to look for regular expression matches in the response output.
1488    *
1489    * <p>
1490    * This method can be called multiple times to add multiple response pattern finders.
1491    *
1492    * <p>
1493    * {@link ResponsePattern ResponsePatterns} use the {@link #getCapturedResponse()} to read the response text and so
1494    * does not affect the other output methods such as {@link #getResponseAsString()}.
1495    *
1496    * @param responsePattern The response pattern finder.
1497    * @return This object (for method chaining).
1498    */
1499   public RestCall responsePattern(final ResponsePattern responsePattern) {
1500      captureResponse();
1501      interceptor(
1502         new RestCallInterceptor() {
1503            @Override
1504            public void onClose(RestCall restCall) throws RestCallException {
1505               responsePattern.match(RestCall.this);
1506            }
1507         }
1508      );
1509      return this;
1510   }
1511
1512   /**
1513    * Set configuration settings on this request.
1514    *
1515    * <p>
1516    * Use {@link RequestConfig#custom()} to create configuration parameters for the request.
1517    *
1518    * @param config The new configuration settings for this request.
1519    * @return This object (for method chaining).
1520    */
1521   public RestCall setConfig(RequestConfig config) {
1522      this.request.setConfig(config);
1523      return this;
1524   }
1525
1526   /**
1527    * Method used to execute an HTTP response where you're only interested in the HTTP response code.
1528    *
1529    * <p>
1530    * The response entity is discarded unless one of the pipe methods have been specified to pipe the output to an
1531    * output stream or writer.
1532    *
1533    * <h5 class='section'>Example:</h5>
1534    * <p class='bcode w800'>
1535    *    <jk>try</jk> {
1536    *       RestClient client = <jk>new</jk> RestClient();
1537    *       <jk>int</jk> rc = client.doGet(url).execute();
1538    *       <jc>// Succeeded!</jc>
1539    *    } <jk>catch</jk> (RestCallException e) {
1540    *       <jc>// Failed!</jc>
1541    *    }
1542    * </p>
1543    *
1544    * @return The HTTP status code.
1545    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
1546    */
1547   public int run() throws RestCallException {
1548      connect();
1549      try {
1550         StatusLine status = response.getStatusLine();
1551         int sc = status.getStatusCode();
1552         if (sc >= 400 && ! ignoreErrors)
1553            throw new RestCallException(sc, status.getReasonPhrase(), request.getMethod(), request.getURI(), getResponseAsString()).setHttpResponse(response);
1554         if (outputStreams.size() > 0 || writers.size() > 0)
1555            getReader();
1556         return sc;
1557      } catch (RestCallException e) {
1558         isFailed = true;
1559         throw e;
1560      } catch (IOException e) {
1561         isFailed = true;
1562         throw new RestCallException(e).setHttpResponse(response);
1563      } finally {
1564         close();
1565      }
1566   }
1567
1568   /**
1569    * Same as {@link #run()} but allows you to run the call asynchronously.
1570    *
1571    * @return The HTTP status code.
1572    * @throws RestCallException If the executor service was not defined.
1573    * @see RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
1574    * {@link Future Futures}.
1575    */
1576   public Future<Integer> runFuture() throws RestCallException {
1577      return client.getExecutorService(true).submit(
1578         new Callable<Integer>() {
1579            @Override /* Callable */
1580            public Integer call() throws Exception {
1581               return run();
1582            }
1583         }
1584      );
1585   }
1586
1587   /**
1588    * Connects to the REST resource.
1589    *
1590    * <p>
1591    * If this is a <c>PUT</c> or <c>POST</c>, also sends the input to the remote resource.<br>
1592    *
1593    * <p>
1594    * Typically, you would only call this method if you're not interested in retrieving the body of the HTTP response.
1595    * Otherwise, you're better off just calling one of the {@link #getReader()}/{@link #getResponse(Class)}/{@link #pipeTo(Writer)}
1596    * methods directly which automatically call this method already.
1597    *
1598    * @return This object (for method chaining).
1599    * @throws RestCallException If an exception or <c>400+</c> HTTP status code occurred during the connection attempt.
1600    */
1601   public RestCall connect() throws RestCallException {
1602      return connect(null);
1603   }
1604
1605   private RestCall connect(ClassMeta<?> bodyType) throws RestCallException {
1606
1607      if (isConnected)
1608         return this;
1609      isConnected = true;
1610
1611      try {
1612         HttpEntityEnclosingRequestBase request2 = request instanceof HttpEntityEnclosingRequestBase ? (HttpEntityEnclosingRequestBase)request : null;
1613
1614         request.setURI(uriBuilder.build());
1615
1616         if (hasInput || formData != null) {
1617
1618            if (hasInput && formData != null)
1619               throw new RestCallException("Both input and form data found on same request.");
1620
1621            if (request2 == null)
1622               throw new RestCallException(0, "Method does not support content entity.", request.getMethod(), request.getURI(), null);
1623
1624            HttpEntity entity = null;
1625            if (formData != null)
1626               entity = new UrlEncodedFormEntity(formData);
1627            else if (input instanceof NameValuePairs)
1628               entity = new UrlEncodedFormEntity((NameValuePairs)input);
1629            else if (input instanceof HttpEntity)
1630               entity = (HttpEntity)input;
1631            else if (input instanceof Reader)
1632               entity = new StringEntity(IOUtils.read((Reader)input), getRequestContentType(TEXT_PLAIN));
1633            else if (input instanceof InputStream)
1634               entity = new InputStreamEntity((InputStream)input, getRequestContentType(ContentType.APPLICATION_OCTET_STREAM));
1635            else if (serializer != null)
1636               entity = new RestRequestEntity(input, serializer, requestBodySchema);
1637            else if (partSerializer != null)
1638               entity = new StringEntity(partSerializer.serialize((HttpPartSchema)null, input), getRequestContentType(TEXT_PLAIN));
1639            else
1640               entity = new StringEntity(getBeanContext().getClassMetaForObject(input).toString(input), getRequestContentType(TEXT_PLAIN));
1641
1642            if (retries > 1 && ! entity.isRepeatable())
1643               throw new RestCallException("Rest call set to retryable, but entity is not repeatable.");
1644
1645            request2.setEntity(entity);
1646         }
1647
1648         int sc = 0;
1649         while (retries > 0) {
1650            retries--;
1651            Exception ex = null;
1652            try {
1653               if (request2 != null)
1654                  response = client.execute(request2);
1655               else
1656                  response = client.execute(request);
1657               sc = (response == null || response.getStatusLine() == null) ? -1 : response.getStatusLine().getStatusCode();
1658            } catch (Exception e) {
1659               ex = e;
1660               sc = -1;
1661               if (response != null)
1662                  EntityUtils.consumeQuietly(response.getEntity());
1663            }
1664            if (! retryOn.onResponse(response))
1665               retries = 0;
1666            if (retries > 0) {
1667               for (RestCallInterceptor rci : interceptors)
1668                  rci.onRetry(this, sc, request, response, ex);
1669               request.reset();
1670               long w = retryInterval;
1671               synchronized(this) {
1672                  wait(w);
1673               }
1674            } else if (ex != null) {
1675               throw ex;
1676            }
1677         }
1678         for (RestCallInterceptor rci : interceptors)
1679            rci.onConnect(this, sc, request, response);
1680         if (response == null)
1681            throw new RestCallException("HttpClient returned a null response");
1682         StatusLine sl = response.getStatusLine();
1683         String method = request.getMethod();
1684         sc = sl.getStatusCode(); // Read it again in case it was changed by one of the interceptors.
1685
1686         int[] expected = new int[0];
1687         if (bodyType != null && bodyType.hasAnnotation(Response.class))
1688            expected = bodyType.getAnnotation(Response.class).code();
1689
1690         if (sc >= 400 && ! ignoreErrors && ! ArrayUtils.contains(sc, expected)) {
1691            throw new RestCallException(sc, sl.getReasonPhrase(), method, request.getURI(), getResponseAsString())
1692               .setServerException(response.getFirstHeader("Exception-Name"), response.getFirstHeader("Exception-Message"), response.getFirstHeader("Exception-Trace"))
1693               .setHttpResponse(response);
1694         }
1695         if ((sc == 307 || sc == 302) && allowRedirectsOnPosts && method.equalsIgnoreCase("POST") && ! ArrayUtils.contains(sc, expected)) {
1696            if (redirectOnPostsTries-- < 1)
1697               throw new RestCallException(sc, "Maximum number of redirects occurred.  Location header: " + response.getFirstHeader("Location"), method, request.getURI(), getResponseAsString());
1698            Header h = response.getFirstHeader("Location");
1699            if (h != null) {
1700               reset();
1701               request.setURI(URI.create(h.getValue()));
1702               retries++;  // Redirects should affect retries.
1703               connect();
1704            }
1705         }
1706
1707      } catch (RestCallException e) {
1708         isFailed = true;
1709         close();
1710         throw e;
1711      } catch (Exception e) {
1712         isFailed = true;
1713         close();
1714         throw new RestCallException(e).setHttpResponse(response);
1715      }
1716
1717      return this;
1718   }
1719
1720   private ContentType getRequestContentType(ContentType def) {
1721      Header h = request.getFirstHeader("Content-Type");
1722      if (h != null) {
1723         String s = h.getValue();
1724         if (! isEmpty(s))
1725            return ContentType.create(s);
1726      }
1727      return def;
1728   }
1729
1730   private void reset() {
1731      if (response != null)
1732         EntityUtils.consumeQuietly(response.getEntity());
1733      request.reset();
1734      isConnected = false;
1735      isClosed = false;
1736      isFailed = false;
1737      if (capturedResponseWriter != null)
1738         capturedResponseWriter.getBuffer().setLength(0);
1739   }
1740
1741   /**
1742    * Connects to the remote resource (if <c>connect()</c> hasn't already been called) and returns the HTTP
1743    * response message body as a reader.
1744    *
1745    * <p>
1746    * If an {@link Encoder} has been registered with the {@link RestClient}, then the underlying input stream will be
1747    * wrapped in the encoded stream (e.g. a <c>GZIPInputStream</c>).
1748    *
1749    * <p>
1750    * If present, automatically handles the <c>charset</c> value in the <c>Content-Type</c> response header.
1751    *
1752    * <p>
1753    * <b>IMPORTANT:</b>  It is your responsibility to close this reader once you have finished with it.
1754    *
1755    * @return
1756    *    The HTTP response message body reader.
1757    *    <jk>null</jk> if response was successful but didn't contain a body (e.g. HTTP 204).
1758    * @throws IOException If an exception occurred while streaming was already occurring.
1759    */
1760   public Reader getReader() throws IOException {
1761      InputStream is = getInputStream();
1762      if (is == null)
1763         return null;
1764
1765      // Figure out what the charset of the response is.
1766      String cs = null;
1767      Header contentType = response.getLastHeader("Content-Type");
1768      String ct = contentType == null ? null : contentType.getValue();
1769
1770      // First look for "charset=" in Content-Type header of response.
1771      if (ct != null && ct.contains("charset="))
1772         cs = ct.substring(ct.indexOf("charset=")+8).trim();
1773
1774      if (cs == null)
1775         cs = "UTF-8";
1776
1777      if (writers.size() > 0) {
1778         try (Reader isr = new InputStreamReader(is, cs)) {
1779            StringWriter sw = new StringWriter();
1780            writers.add(sw, true);
1781            IOPipe.create(isr, writers).byLines(byLines).run();
1782            return new StringReader(sw.toString());
1783         }
1784      }
1785
1786      return new InputStreamReader(is, cs);
1787   }
1788
1789   /**
1790    * Returns the response text as a string if {@link #captureResponse()} was called on this object.
1791    *
1792    * <p>
1793    * Note that while similar to {@link #getResponseAsString()}, this method can be called multiple times to retrieve
1794    * the response text multiple times.
1795    *
1796    * <p>
1797    * Note that this method returns <jk>null</jk> if you have not called one of the methods that cause the response to
1798    * be processed.  (e.g. {@link #run()}, {@link #getResponse()}, {@link #getResponseAsString()}.
1799    *
1800    * @return The captured response, or <jk>null</jk> if {@link #captureResponse()} has not been called.
1801    * @throws IllegalStateException If trying to call this method before the response is consumed.
1802    */
1803   public String getCapturedResponse() {
1804      if (! isClosed)
1805         throw new IllegalStateException("This method cannot be called until the response has been consumed.");
1806      if (capturedResponse == null && capturedResponseWriter != null && capturedResponseWriter.getBuffer().length() > 0)
1807         capturedResponse = capturedResponseWriter.toString();
1808      return capturedResponse;
1809   }
1810
1811   /**
1812    * Returns the value of the <c>Content-Length</c> header.
1813    *
1814    * @return The value of the <c>Content-Length</c> header, or <c>-1</c> if header is not present.
1815    * @throws IOException Thrown by underlying stream.
1816    */
1817   public int getContentLength() throws IOException {
1818      connect();
1819      Header h = response.getLastHeader("Content-Length");
1820      if (h == null)
1821         return -1;
1822      long l = Long.parseLong(h.getValue());
1823      if (l > Integer.MAX_VALUE)
1824         return Integer.MAX_VALUE;
1825      return (int)l;
1826   }
1827
1828   /**
1829    * Connects to the remote resource (if <c>connect()</c> hasn't already been called) and returns the HTTP
1830    * response message body as an input stream.
1831    *
1832    * <p>
1833    * If an {@link Encoder} has been registered with the {@link RestClient}, then the underlying input stream will be
1834    * wrapped in the encoded stream (e.g. a <c>GZIPInputStream</c>).
1835    *
1836    * <p>
1837    * <b>IMPORTANT:</b>  It is your responsibility to close this reader once you have finished with it.
1838    *
1839    * @return
1840    *    The HTTP response message body input stream. <jk>null</jk> if response was successful but didn't contain
1841    *    a body (e.g. HTTP 204).
1842    * @throws IOException If an exception occurred while streaming was already occurring.
1843    * @throws IllegalStateException If an attempt is made to read the response more than once.
1844    */
1845   @SuppressWarnings("resource")
1846   public InputStream getInputStream() throws IOException {
1847      if (isClosed)
1848         throw new IllegalStateException("Method cannot be called.  Response has already been consumed.");
1849      connect();
1850      if (response == null)
1851         throw new RestCallException("Response was null");
1852      if (response.getEntity() == null)  // HTTP 204 results in no content.
1853         return null;
1854
1855      softClose();
1856
1857      InputStream is = new EofSensorInputStream(response.getEntity().getContent(), new EofSensorWatcher() {
1858         @Override
1859         public boolean eofDetected(InputStream wrapped) throws IOException {
1860            RestCall.this.forceClose();
1861            return true;
1862         }
1863         @Override
1864         public boolean streamClosed(InputStream wrapped) throws IOException {
1865            RestCall.this.forceClose();
1866            return true;
1867         }
1868         @Override
1869         public boolean streamAbort(InputStream wrapped) throws IOException {
1870            RestCall.this.forceClose();
1871            return true;
1872         }
1873      });
1874
1875      if (outputStreams.size() > 0) {
1876         ByteArrayInOutStream baios = new ByteArrayInOutStream();
1877         outputStreams.add(baios, true);
1878         IOPipe.create(is, baios).run();
1879         is.close();
1880         return baios.getInputStream();
1881      }
1882      return is;
1883   }
1884
1885   /**
1886    * Connects to the remote resource (if {@code connect()} hasn't already been called) and returns the HTTP response
1887    * message body as plain text.
1888    *
1889    * <p>
1890    * The response entity is discarded unless one of the pipe methods have been specified to pipe the output to an
1891    * output stream or writer.
1892    *
1893    * @return The response as a string.
1894    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
1895    * @throws IOException If an exception occurred while streaming was already occurring.
1896    */
1897   public String getResponseAsString() throws IOException {
1898      try (Reader r = getReader()) {
1899         return read(r).toString();
1900      } catch (IOException e) {
1901         isFailed = true;
1902         close();
1903         throw e;
1904      }
1905   }
1906
1907   /**
1908    * Connects to the remote resource (if {@code connect()} hasn't already been called) and returns the value of
1909    * an HTTP header on the response.
1910    *
1911    * <p>
1912    * Useful if you're only interested in a particular header value from the response and not the body of the response.
1913    *
1914    * <p>
1915    * The response entity is discarded unless one of the pipe methods have been specified to pipe the output to an
1916    * output stream or writer.
1917    *
1918    * @param name The header name.
1919    * @return The response header as a string, or <jk>null</jk> if the header was not found.
1920    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
1921    * @throws IOException If an exception occurred while streaming was already occurring.
1922    */
1923   public String getResponseHeader(String name) throws IOException {
1924      try {
1925         HttpResponse r = getResponse();
1926         Header h = r.getFirstHeader(name);
1927         return h == null ? null : h.getValue();
1928      } catch (IOException e) {
1929         isFailed = true;
1930         close();
1931         throw e;
1932      }
1933   }
1934
1935   /**
1936    * Same as {@link #getResponseHeader(String)} except parses the header value using the specified part parser and schema.
1937    *
1938    * @param name The header name.
1939    * @param partParser The part parser to use for parsing the header.
1940    * @param schema The part schema.  Can be <jk>null</jk>.
1941    * @param c The type to convert the part into.
1942    * @return The parsed part.
1943    * @throws IOException Thrown by underlying stream.
1944    * @throws ParseException Header value could not be parsed into the specified type.
1945    */
1946   public <T> T getResponseHeader(HttpPartParser partParser, HttpPartSchema schema, String name, Class<T> c) throws IOException, ParseException {
1947      return getResponseHeader(partParser, schema, name, (Type)c);
1948   }
1949
1950   /**
1951    * Same as {@link #getResponseHeader(String)} except parses the header value using the specified part parser and schema.
1952    *
1953    * @param name The header name.
1954    * @param partParser The part parser to use for parsing the header.
1955    * @param schema The part schema.  Can be <jk>null</jk>.
1956    * @param type The type to convert the part into.
1957    * @param args The type arguments to convert the part into.
1958    * @return The parsed part.
1959    * @throws IOException Thrown by underlying stream.
1960    * @throws ParseException Header value could not be parsed into the specified type.
1961    */
1962   public <T> T getResponseHeader(HttpPartParser partParser, HttpPartSchema schema, String name, Type type, Type...args) throws IOException, ParseException {
1963      try {
1964         HttpResponse r = getResponse();
1965         Header h = r.getFirstHeader(name);
1966         if (h == null)
1967            return null;
1968         String hs = h.getValue();
1969         if (partParser == null)
1970            partParser = client.getPartParser();
1971         return partParser.parse(schema, hs, type, args);
1972      } catch (IOException e) {
1973         isFailed = true;
1974         close();
1975         throw e;
1976      }
1977   }
1978
1979   /**
1980    * Connects to the remote resource (if {@code connect()} hasn't already been called) and returns the HTTP response code.
1981    *
1982    * <p>
1983    * Useful if you're only interested in the status code and not the body of the response.
1984    *
1985    * <p>
1986    * The response entity is discarded unless one of the pipe methods have been specified to pipe the output to an
1987    * output stream or writer.
1988    *
1989    * @return The response code.
1990    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
1991    * @throws IOException If an exception occurred while streaming was already occurring.
1992    */
1993   public int getResponseCode() throws IOException {
1994      return run();
1995   }
1996
1997   /**
1998    * Same as {@link #getResponse(Class)} but allows you to run the call asynchronously.
1999    *
2000    * @return The response as a string.
2001    * @throws RestCallException If the executor service was not defined.
2002    * @see
2003    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
2004    *    {@link Future Futures}.
2005    */
2006   public Future<String> getResponseAsStringFuture() throws RestCallException {
2007      return client.getExecutorService(true).submit(
2008         new Callable<String>() {
2009            @Override /* Callable */
2010            public String call() throws Exception {
2011               return getResponseAsString();
2012            }
2013         }
2014      );
2015   }
2016
2017   /**
2018    * Same as {@link #getResponse(Type, Type...)} except optimized for a non-parameterized class.
2019    *
2020    * <p>
2021    * This is the preferred parse method for simple types since you don't need to cast the results.
2022    *
2023    * <h5 class='section'>Examples:</h5>
2024    * <p class='bcode w800'>
2025    *    <jc>// Parse into a string.</jc>
2026    *    String s = restClient.doGet(url).getResponse(String.<jk>class</jk>);
2027    *
2028    *    <jc>// Parse into a bean.</jc>
2029    *    MyBean b = restClient.doGet(url).getResponse(MyBean.<jk>class</jk>);
2030    *
2031    *    <jc>// Parse into a bean array.</jc>
2032    *    MyBean[] ba = restClient.doGet(url).getResponse(MyBean[].<jk>class</jk>);
2033    *
2034    *    <jc>// Parse into a linked-list of objects.</jc>
2035    *    List l = restClient.doGet(url).getResponse(LinkedList.<jk>class</jk>);
2036    *
2037    *    <jc>// Parse into a map of object keys/values.</jc>
2038    *    Map m = restClient.doGet(url).getResponse(TreeMap.<jk>class</jk>);
2039    * </p>
2040    *
2041    * <ul class='notes'>
2042    *    <li>
2043    *       You can also specify any of the following types:
2044    *       <ul>
2045    *          <li>{@link HttpResponse} - Returns the raw <c>HttpResponse</c> returned by the inner <c>HttpClient</c>.
2046    *          <li>{@link Reader} - Returns access to the raw reader of the response.
2047    *          <li>{@link InputStream} - Returns access to the raw input stream of the response.
2048    *       </ul>
2049    * </ul>
2050    *
2051    * @param <T>
2052    *    The class type of the object being created.
2053    *    See {@link #getResponse(Type, Type...)} for details.
2054    * @param type The object type to create.
2055    * @return The parsed object.
2056    * @throws ParseException
2057    *    If the input contains a syntax error or is malformed, or is not valid for the specified type.
2058    * @throws IOException If a connection error occurred.
2059    */
2060   public <T> T getResponse(Class<T> type) throws IOException, ParseException {
2061      BeanContext bc = parser;
2062      if (bc == null)
2063         bc = BeanContext.DEFAULT;
2064      return getResponseInner(bc.getClassMeta(type));
2065   }
2066
2067   /**
2068    * Same as {@link #getResponse(Class)} but allows you to run the call asynchronously.
2069    *
2070    * @param <T>
2071    *    The class type of the object being created.
2072    *    See {@link #getResponse(Type, Type...)} for details.
2073    * @param type The object type to create.
2074    * @return The parsed object.
2075    * @throws RestCallException If the executor service was not defined.
2076    * @see
2077    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
2078    *    {@link Future Futures}.
2079    */
2080   public <T> Future<T> getResponseFuture(final Class<T> type) throws RestCallException {
2081      return client.getExecutorService(true).submit(
2082         new Callable<T>() {
2083            @Override /* Callable */
2084            public T call() throws Exception {
2085               return getResponse(type);
2086            }
2087         }
2088      );
2089   }
2090
2091   /**
2092    * Parses HTTP body into the specified object type.
2093    *
2094    * <p>
2095    * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
2096    *
2097    * <h5 class='section'>Examples:</h5>
2098    * <p class='bcode w800'>
2099    *    <jc>// Parse into a linked-list of strings.</jc>
2100    *    List l = restClient.doGet(url).getResponse(LinkedList.<jk>class</jk>, String.<jk>class</jk>);
2101    *
2102    *    <jc>// Parse into a linked-list of beans.</jc>
2103    *    List l = restClient.doGet(url).getResponse(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
2104    *
2105    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
2106    *    List l = restClient.doGet(url).getResponse(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
2107    *
2108    *    <jc>// Parse into a map of string keys/values.</jc>
2109    *    Map m = restClient.doGet(url).getResponse(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
2110    *
2111    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
2112    *    Map m = restClient.doGet(url).getResponse(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
2113    * </p>
2114    *
2115    * <p>
2116    * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
2117    *
2118    * <p>
2119    * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
2120    *
2121    * <p>
2122    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
2123    *
2124    * <ul class='notes'>
2125    *    <li>
2126    *       Use the {@link #getResponse(Class)} method instead if you don't need a parameterized map/collection.
2127    *    <li>
2128    *       You can also specify any of the following types:
2129    *       <ul>
2130    *          <li>{@link HttpResponse} - Returns the raw <c>HttpResponse</c> returned by the inner <c>HttpClient</c>.
2131    *          <li>{@link Reader} - Returns access to the raw reader of the response.
2132    *          <li>{@link InputStream} - Returns access to the raw input stream of the response.
2133    *       </ul>
2134    * </ul>
2135    *
2136    * @param <T> The class type of the object to create.
2137    * @param type
2138    *    The object type to create.
2139    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
2140    * @param args
2141    *    The type arguments of the class if it's a collection or map.
2142    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
2143    *    <br>Ignored if the main type is not a map or collection.
2144    * @return The parsed object.
2145    * @throws ParseException
2146    *    If the input contains a syntax error or is malformed, or is not valid for the specified type.
2147    * @throws IOException If a connection error occurred.
2148    * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
2149    */
2150   public <T> T getResponse(Type type, Type...args) throws IOException, ParseException {
2151      BeanContext bc = parser;
2152      if (bc == null)
2153         bc = BeanContext.DEFAULT;
2154      return (T)getResponseInner(bc.getClassMeta(type, args));
2155   }
2156
2157   /**
2158    * Same as {@link #getResponse(Type, Type...)} but allows you to specify a part parser to use for parsing the response.
2159    *
2160    * @param <T> The class type of the object to create.
2161    * @param type
2162    *    The object type to create.
2163    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
2164    * @param args
2165    *    The type arguments of the class if it's a collection or map.
2166    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
2167    *    <br>Ignored if the main type is not a map or collection.
2168    * @return The parsed object.
2169    * @throws ParseException
2170    *    If the input contains a syntax error or is malformed, or is not valid for the specified type.
2171    * @throws IOException If a connection error occurred.
2172    * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
2173    */
2174   public <T> T getResponseBody(Type type, Type...args) throws IOException, ParseException {
2175      BeanContext bc = parser;
2176      if (bc == null)
2177         bc = BeanContext.DEFAULT;
2178      return (T)getResponseInner(bc.getClassMeta(type, args));
2179   }
2180
2181   /**
2182    * Same as {@link #getResponse(Class)} but allows you to run the call asynchronously.
2183    *
2184    * @param <T>
2185    *    The class type of the object being created.
2186    *    See {@link #getResponse(Type, Type...)} for details.
2187    * @param type
2188    *    The object type to create.
2189    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
2190    * @param args
2191    *    The type arguments of the class if it's a collection or map.
2192    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
2193    *    <br>Ignored if the main type is not a map or collection.
2194    * @return The parsed object.
2195    * @throws RestCallException If the executor service was not defined.
2196    * @see
2197    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
2198    *    {@link Future Futures}.
2199    */
2200   public <T> Future<T> getResponseFuture(final Type type, final Type...args) throws RestCallException {
2201      return client.getExecutorService(true).submit(
2202         new Callable<T>() {
2203            @Override /* Callable */
2204            public T call() throws Exception {
2205               return getResponse(type, args);
2206            }
2207         }
2208      );
2209   }
2210
2211   /**
2212    * Parses the output from the connection into the specified type and then wraps that in a {@link PojoRest}.
2213    *
2214    * <p>
2215    * Useful if you want to quickly retrieve a single value from inside of a larger JSON document.
2216    *
2217    * @param innerType The class type of the POJO being wrapped.
2218    * @return The parsed output wrapped in a {@link PojoRest}.
2219    * @throws IOException If a connection error occurred.
2220    * @throws ParseException
2221    *    If the input contains a syntax error or is malformed for the <c>Content-Type</c> header.
2222    */
2223   public PojoRest getResponsePojoRest(Class<?> innerType) throws IOException, ParseException {
2224      return new PojoRest(getResponse(innerType));
2225   }
2226
2227   /**
2228    * Converts the output from the connection into an {@link ObjectMap} and then wraps that in a {@link PojoRest}.
2229    *
2230    * <p>
2231    * Useful if you want to quickly retrieve a single value from inside of a larger JSON document.
2232    *
2233    * @return The parsed output wrapped in a {@link PojoRest}.
2234    * @throws IOException If a connection error occurred.
2235    * @throws ParseException
2236    *    If the input contains a syntax error or is malformed for the <c>Content-Type</c> header.
2237    */
2238   public PojoRest getResponsePojoRest() throws IOException, ParseException {
2239      return getResponsePojoRest(ObjectMap.class);
2240   }
2241
2242   <T> T getResponseInner(ClassMeta<T> type) throws IOException, ParseException {
2243      try {
2244         if (response == null)
2245            connect(type);
2246
2247         Class<?> ic = type.getInnerClass();
2248
2249         if (ic.equals(HttpResponse.class)) {
2250            softClose();
2251            return (T)response;
2252         }
2253         if (ic.equals(Reader.class))
2254            return (T)getReader();
2255         if (ic.equals(InputStream.class))
2256            return (T)getInputStream();
2257         if (type.isType(ReaderResource.class) || type.isType(StreamResource.class)) {
2258            String mediaType = null;
2259            ObjectMap headers = new ObjectMap();
2260            for (Header h : response.getAllHeaders()) {
2261               if (h.getName().equalsIgnoreCase("Content-Type"))
2262                  mediaType = h.getValue();
2263               else
2264                  headers.put(h.getName(), h.getValue());
2265            }
2266            if (type.isType(ReaderResource.class))
2267               return (T)ReaderResource.create().headers(headers).mediaType(mediaType).contents(getReader()).build();
2268            return (T)StreamResource.create().headers(headers).mediaType(mediaType).contents(getInputStream()).build();
2269         }
2270
2271         connect(type);
2272         Header h = response.getFirstHeader("Content-Type");
2273         int sc = response.getStatusLine().getStatusCode();
2274         String ct = firstNonEmpty(h == null ? null : h.getValue(), "text/plain");
2275
2276         MediaType mt = MediaType.forString(ct);
2277
2278         if (parser == null || (mt.toString().equals("text/plain") && ! parser.canHandle(ct))) {
2279            if (type.hasStringMutater())
2280               return type.getStringMutater().mutate(getResponseAsString());
2281         }
2282
2283         if (parser != null) {
2284            try (Closeable in = parser.isReaderParser() ? getReader() : getInputStream()) {
2285
2286               // HttpClient automatically ignores the content body for certain HTTP status codes.
2287               // So instantiate the object anyway if it has a no-arg constructor.
2288               // This allows a remote resource method to return a NoContent object for example.
2289               if (in == null && (sc < SC_OK || sc == SC_NO_CONTENT || sc == SC_NOT_MODIFIED || sc == SC_RESET_CONTENT)) {
2290                  ConstructorInfo c = type.getInfo().getPublicConstructor();
2291                  if (c != null) {
2292                     try {
2293                        return c.<T>invoke();
2294                     } catch (ExecutableException e) {
2295                        throw new ParseException(e);
2296                     }
2297                  }
2298               }
2299
2300               ParserSessionArgs pArgs =
2301                  ParserSessionArgs
2302                     .create()
2303                     .properties(new ObjectMap().setInner(getProperties()))
2304                     .locale(response.getLocale())
2305                     .mediaType(mt)
2306                     .schema(responseBodySchema);
2307               return parser.createSession(pArgs).parse(in, type);
2308            }
2309         }
2310
2311         if (type.hasReaderMutater())
2312            return type.getReaderMutater().mutate(getReader());
2313
2314         if (type.hasInputStreamMutater())
2315            return type.getInputStreamMutater().mutate(getInputStream());
2316
2317         throw new ParseException(
2318            "Unsupported media-type in request header ''Content-Type'': ''{0}''\n\tSupported media-types: {1}",
2319            getResponseHeader("Content-Type"), parser == null ? null : parser.getMediaTypes()
2320         );
2321
2322      } catch (ParseException | IOException e) {
2323         isFailed = true;
2324         close();
2325         throw e;
2326      }
2327   }
2328
2329   BeanContext getBeanContext() {
2330      BeanContext bc = parser;
2331      if (bc == null)
2332         bc = BeanContext.DEFAULT;
2333      return bc;
2334   }
2335
2336   /**
2337    * Converts the response from this call into a response bean.
2338    *
2339    * @param rbm The metadata used to construct the response bean.
2340    * @return A new response bean.
2341    */
2342   public <T> T getResponse(final ResponseBeanMeta rbm) {
2343      try {
2344         softClose();
2345         Class<T> c = (Class<T>)rbm.getClassMeta().getInnerClass();
2346         final RestClient rc = this.client;
2347         final HttpPartParser p = ObjectUtils.firstNonNull(partParser, rc.getPartParser());
2348         return (T)Proxy.newProxyInstance(
2349            c.getClassLoader(),
2350            new Class[] { c },
2351            new InvocationHandler() {
2352               @Override /* InvocationHandler */
2353               public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
2354                  ResponseBeanPropertyMeta pm = rbm.getProperty(method.getName());
2355                  if (pm != null) {
2356                     HttpPartParser pp = pm.getParser(p);
2357                     HttpPartSchema schema = pm.getSchema();
2358                     String name = pm.getPartName();
2359                     ClassMeta<?> type = rc.getClassMeta(method.getGenericReturnType());
2360                     HttpPartType pt = pm.getPartType();
2361                     if (pt == RESPONSE_BODY) {
2362                        responseBodySchema(schema);
2363                        return getResponseBody(type);
2364                     }
2365                     if (pt == RESPONSE_HEADER)
2366                        return getResponseHeader(pp, schema, name, type);
2367                     if (pt == RESPONSE_STATUS)
2368                        return getResponseCode();
2369                  }
2370                  return null;
2371               }
2372
2373         });
2374      } catch (Exception e) {
2375         throw new RuntimeException(e);
2376      }
2377   }
2378
2379   /**
2380    * Returns access to the {@link HttpUriRequest} passed to {@link HttpClient#execute(HttpUriRequest)}.
2381    *
2382    * @return The {@link HttpUriRequest} object.
2383    */
2384   public HttpUriRequest getRequest() {
2385      return request;
2386   }
2387
2388   /**
2389    * Returns access to the {@link HttpResponse} returned by {@link HttpClient#execute(HttpUriRequest)}.
2390    *
2391    * <p>
2392    * Returns <jk>null</jk> if {@link #connect()} has not yet been called.
2393    *
2394    * @return The HTTP response object.
2395    * @throws IOException Thrown by underlying stream.
2396    */
2397   public HttpResponse getResponse() throws IOException {
2398      connect();
2399      return response;
2400   }
2401
2402   /**
2403    * Shortcut for calling <c>getRequest().setHeader(header)</c>
2404    *
2405    * @param header The header to set on the request.
2406    * @return This object (for method chaining).
2407    */
2408   public RestCall header(Header header) {
2409      request.setHeader(header);
2410      return this;
2411   }
2412
2413   /**
2414    * Cleans up this HTTP call.
2415    *
2416    * @throws RestCallException Can be thrown by one of the {@link RestCallInterceptor#onClose(RestCall)} calls.
2417    */
2418   @Override /* Closeable */
2419   public void close() throws RestCallException {
2420      if (response != null && ! softClose)
2421         EntityUtils.consumeQuietly(response.getEntity());
2422      if (! softClose)
2423         isClosed = true;
2424      if (! isFailed)
2425         for (RestCallInterceptor r : interceptors)
2426            r.onClose(this);
2427   }
2428
2429   void forceClose() throws RestCallException {
2430      softClose = false;
2431      close();
2432   }
2433
2434   /**
2435    * Adds a {@link RestCallLogger} to the list of interceptors on this class.
2436    *
2437    * @param level The log level to log events at.
2438    * @param log The logger.
2439    * @return This object (for method chaining).
2440    */
2441   public RestCall logTo(Level level, Logger log) {
2442      interceptor(new RestCallLogger(level, log));
2443      return this;
2444   }
2445
2446   /**
2447    * Sets <c>Debug: value</c> header on this request.
2448    *
2449    * @return This object (for method chaining).
2450    * @throws RestCallException Invalid input.
2451    */
2452   public RestCall debug() throws RestCallException {
2453      header("Debug", true);
2454      return this;
2455   }
2456
2457   /**
2458    * If called, the underlying response stream will not be closed when you call {@link #close()}.
2459    *
2460    * <p>
2461    * This is useful in cases where you want access to that stream after you've already cleaned up this object.
2462    * However, it is your responsibility to close that stream yourself.
2463    *
2464    * @return This object (for method chaining).
2465    */
2466   public RestCall softClose() {
2467      this.softClose = true;
2468      return this;
2469   }
2470
2471   //-----------------------------------------------------------------------------------------------------------------
2472   // Utility methods
2473   //-----------------------------------------------------------------------------------------------------------------
2474
2475   /**
2476    * Specifies that the following value can be added as an HTTP part.
2477    */
2478   private boolean canAdd(Object value, HttpPartSchema schema, boolean skipIfEmpty) {
2479      if (value != null) {
2480         if (ObjectUtils.isEmpty(value) && skipIfEmpty)
2481            return false;
2482         return true;
2483      }
2484      if (schema == null)
2485         return false;
2486      if (schema.isRequired())
2487         return true;
2488      String def = schema.getDefault();
2489      if (def == null)
2490         return false;
2491      if (StringUtils.isEmpty(def) && skipIfEmpty)
2492         return false;
2493      return true;
2494   }
2495
2496   private static String className(Object o) {
2497      return ClassInfo.of(o).getFullName();
2498   }
2499
2500   //-----------------------------------------------------------------------------------------------------------------
2501   // Other methods
2502   //-----------------------------------------------------------------------------------------------------------------
2503
2504   @Override /* Session */
2505   public ObjectMap toMap() {
2506      return super.toMap()
2507         .append("RestCall", new DefaultFilteringObjectMap()
2508            .append("allowRedirectsOnPosts", allowRedirectsOnPosts)
2509            .append("byLines", byLines)
2510            .append("capturedResponse", capturedResponse)
2511            .append("client", client)
2512            .append("hasInput", hasInput)
2513            .append("ignoreErrors", ignoreErrors)
2514            .append("interceptors", interceptors)
2515            .append("isClosed", isClosed)
2516            .append("isConnected", isConnected)
2517            .append("isFailed", isFailed)
2518            .append("parser", parser)
2519            .append("partParser", partParser)
2520            .append("partSerializer", partSerializer)
2521            .append("redirectOnPostsTries", redirectOnPostsTries)
2522            .append("requestBodySchema", requestBodySchema)
2523            .append("response", response)
2524            .append("responseBodySchema", responseBodySchema)
2525            .append("retries", retries)
2526            .append("retryInterval", retryInterval)
2527            .append("retryOn", retryOn)
2528            .append("serializer", serializer)
2529            .append("softClose", softClose)
2530            .append("uriBuilder", uriBuilder)
2531         );
2532   }
2533}