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