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