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.common.internal.IOUtils.*;
016import static org.apache.juneau.common.internal.StringUtils.*;
017import static org.apache.juneau.common.internal.ThrowableUtils.*;
018
019import java.io.*;
020import java.lang.reflect.*;
021import java.nio.charset.*;
022import java.util.concurrent.*;
023import java.util.regex.*;
024import java.util.regex.Matcher;
025
026import org.apache.http.*;
027import org.apache.http.conn.*;
028import org.apache.juneau.*;
029import org.apache.juneau.assertions.*;
030import org.apache.juneau.collections.*;
031import org.apache.juneau.common.internal.*;
032import org.apache.juneau.http.entity.*;
033import org.apache.juneau.http.resource.*;
034import org.apache.juneau.httppart.*;
035import org.apache.juneau.internal.*;
036import org.apache.juneau.oapi.*;
037import org.apache.juneau.objecttools.*;
038import org.apache.juneau.parser.*;
039import org.apache.juneau.parser.ParseException;
040import org.apache.juneau.reflect.*;
041import org.apache.juneau.rest.client.assertion.*;
042
043/**
044 * Represents the body of an HTTP response.
045 *
046 * <p>
047 * An extension of an HttpClient {@link HttpEntity} that provides various support for converting the body to POJOs and
048 * other convenience methods.
049 *
050 * <h5 class='section'>See Also:</h5><ul>
051 *    <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-client">juneau-rest-client</a>
052 * </ul>
053 */
054public class ResponseContent implements HttpEntity {
055
056   private static final HttpEntity NULL_ENTITY = new HttpEntity() {
057
058      @Override
059      public boolean isRepeatable() {
060         return false;
061      }
062
063      @Override
064      public boolean isChunked() {
065         return false;
066      }
067
068      @Override
069      public long getContentLength() {
070         return -1;
071      }
072
073      @Override
074      public Header getContentType() {
075         return ResponseHeader.NULL_HEADER;
076      }
077
078      @Override
079      public Header getContentEncoding() {
080         return ResponseHeader.NULL_HEADER;
081      }
082
083      @Override
084      public InputStream getContent() throws IOException, UnsupportedOperationException {
085         return new ByteArrayInputStream(new byte[0]);
086      }
087
088      @Override
089      public void writeTo(OutputStream outstream) throws IOException {}
090
091      @Override
092      public boolean isStreaming() {
093         return false;
094      }
095
096      @Override
097      public void consumeContent() throws IOException {}
098   };
099
100   private final RestClient client;
101   final RestRequest request;
102   final RestResponse response;
103   private final HttpEntity entity;
104   private HttpPartSchema schema;
105   private Parser parser;
106   private byte[] body;
107   private boolean cached;
108   boolean isConsumed;
109
110   /**
111    * Constructor.
112    *
113    * @param client The client used to build this request.
114    * @param request The request object.
115    * @param response The response object.
116    * @param parser The parser to use to consume the body.  Can be <jk>null</jk>.
117    */
118   public ResponseContent(RestClient client, RestRequest request, RestResponse response, Parser parser) {
119      this.client = client;
120      this.request = request;
121      this.response = response;
122      this.parser = parser;
123      this.entity = ObjectUtils.firstNonNull(response.asHttpResponse().getEntity(), NULL_ENTITY);
124   }
125
126   //------------------------------------------------------------------------------------------------------------------
127   // Setters
128   //------------------------------------------------------------------------------------------------------------------
129
130   /**
131    * Specifies the parser to use for this body.
132    *
133    * <p>
134    * If not specified, uses the parser defined on the client set via {@link RestClient.Builder#parser(Class)}.
135    *
136    * @param value
137    *    The new part parser to use for this body.
138    * @return This object.
139    */
140   public ResponseContent parser(Parser value) {
141      this.parser = value;
142      return this;
143   }
144
145   /**
146    * Specifies the schema for this body.
147    *
148    * <p>
149    * Used by schema-based parsers such as {@link OpenApiParser}.
150    *
151    * @param value The schema.
152    * @return This object.
153    */
154   public ResponseContent schema(HttpPartSchema value) {
155      this.schema = value;
156      return this;
157   }
158
159   /**
160    * Causes the contents of the response body to be stored so that it can be repeatedly read.
161    *
162    * <p>
163    * Calling this method allows methods that read the response body to be called multiple times.
164    *
165    * <h5 class='section'>Notes:</h5><ul>
166    *    <li class='note'>
167    *       Multiple calls to this method are ignored.
168    * </ul>
169    *
170    * @return This object.
171    */
172   public ResponseContent cache() {
173      this.cached = true;
174      return this;
175   }
176
177   //------------------------------------------------------------------------------------------------------------------
178   // Raw streams
179   //------------------------------------------------------------------------------------------------------------------
180
181   /**
182    * Returns the HTTP response message body as an input stream.
183    *
184    * <h5 class='section'>Notes:</h5><ul>
185    *    <li class='note'>
186    *       Once this input stream is exhausted, it will automatically be closed.
187    *  <li class='note'>
188    *    This method can be called multiple times if {@link #cache()} has been called.
189    *  <li class='note'>
190    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
191    *    with an inner {@link IllegalStateException} to be thrown.
192    * </ul>
193    *
194    * @return
195    *    The HTTP response message body input stream, never <jk>null</jk>.
196    *    <br>For responses without a body(e.g. HTTP 204), returns an empty stream.
197    * @throws IOException If a stream or illegal state exception was thrown.
198    */
199   @SuppressWarnings("resource")
200   public InputStream asInputStream() throws IOException {
201      try {
202         if (body != null)
203            return new ByteArrayInputStream(body);
204
205         if (cached) {
206            body = readBytes(entity.getContent());
207            response.close();
208            return new ByteArrayInputStream(body);
209         }
210
211         if (isConsumed && ! entity.isRepeatable())
212            throw new IllegalStateException("Method cannot be called.  Response has already been consumed.  Consider using the RestResponse.cacheBody() method.");
213
214         HttpEntity e = response.asHttpResponse().getEntity();
215         InputStream is = e == null ? new ByteArrayInputStream(new byte[0]) : e.getContent();
216
217         is = new EofSensorInputStream(is, new EofSensorWatcher() {
218            @Override
219            public boolean eofDetected(InputStream wrapped) throws IOException {
220               try {
221                  response.close();
222               } catch (RestCallException e) {}
223               return true;
224            }
225            @Override
226            public boolean streamClosed(InputStream wrapped) throws IOException {
227               try {
228                  response.close();
229               } catch (RestCallException e) {}
230               return true;
231            }
232            @Override
233            public boolean streamAbort(InputStream wrapped) throws IOException {
234               try {
235                  response.close();
236               } catch (RestCallException e) {}
237               return true;
238            }
239         });
240
241         isConsumed = true;
242
243         return is;
244      } catch (UnsupportedOperationException | RestCallException e) {
245         throw new IOException(e);
246      }
247   }
248
249   /**
250    * Returns the HTTP response message body as a reader based on the charset on the <code>Content-Type</code> response header.
251    *
252    * <h5 class='section'>Notes:</h5><ul>
253    *    <li class='note'>
254    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
255    *    <li class='note'>
256    *       Once this input stream is exhausted, it will automatically be closed.
257    *  <li class='note'>
258    *    This method can be called multiple times if {@link #cache()} has been called.
259    *  <li class='note'>
260    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
261    *    with an inner {@link IllegalStateException} to be thrown.
262    * </ul>
263    *
264    * @return
265    *    The HTTP response message body reader, never <jk>null</jk>.
266    *    <br>For responses without a body(e.g. HTTP 204), returns an empty reader.
267    * @throws IOException If an exception occurred.
268    */
269   public Reader asReader() throws IOException {
270
271      // Figure out what the charset of the response is.
272      String cs = null;
273      String ct = getContentType().orElse(null);
274
275      // First look for "charset=" in Content-Type header of response.
276      if (ct != null)
277         if (ct.contains("charset="))
278            cs = ct.substring(ct.indexOf("charset=")+8).trim();
279
280      return asReader(cs == null ? IOUtils.UTF8 : Charset.forName(cs));
281   }
282
283   /**
284    * Returns the HTTP response message body as a reader using the specified charset.
285    *
286    * <h5 class='section'>Notes:</h5><ul>
287    *    <li class='note'>
288    *       Once this input stream is exhausted, it will automatically be closed.
289    *  <li class='note'>
290    *    This method can be called multiple times if {@link #cache()} has been called.
291    *  <li class='note'>
292    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
293    *    with an inner {@link IllegalStateException} to be thrown.
294    * </ul>
295    *
296    * @param charset
297    *    The charset to use for the reader.
298    *    <br>If <jk>null</jk>, <js>"UTF-8"</js> is used.
299    * @return
300    *    The HTTP response message body reader, never <jk>null</jk>.
301    *    <br>For responses without a body(e.g. HTTP 204), returns an empty reader.
302    * @throws IOException If an exception occurred.
303    */
304   public Reader asReader(Charset charset) throws IOException {
305      return new InputStreamReader(asInputStream(), charset == null ? IOUtils.UTF8 : charset);
306   }
307
308   /**
309    * Returns the HTTP response message body as a byte array.
310    *
311    *    The HTTP response message body reader, never <jk>null</jk>.
312    *    <br>For responses without a body(e.g. HTTP 204), returns an empty array.
313    *
314    * @return The HTTP response body as a byte array.
315    * @throws RestCallException If an exception occurred.
316    */
317   public byte[] asBytes() throws RestCallException {
318      if (body == null) {
319         try {
320            if (entity instanceof BasicHttpEntity) {
321               body = ((BasicHttpEntity)entity).asBytes();
322            } else {
323               body = readBytes(entity.getContent());
324            }
325         } catch (IOException e) {
326            throw new RestCallException(response, e, "Could not read response body.");
327         } finally {
328            response.close();
329         }
330      }
331      return body;
332   }
333
334
335   /**
336    * Pipes the contents of the response to the specified output stream.
337    *
338    * <h5 class='section'>Notes:</h5><ul>
339    * <li class='note'>
340    *    The output stream is not automatically closed.
341    *    <li class='note'>
342    *       Once the input stream is exhausted, it will automatically be closed.
343    *  <li class='note'>
344    *    This method can be called multiple times if {@link #cache()} has been called.
345    *  <li class='note'>
346    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
347    *    with an inner {@link IllegalStateException} to be thrown.
348    * </ul>
349    *
350    * @param os The output stream to pipe the output to.
351    * @return This object.
352    * @throws IOException If an IO exception occurred.
353    */
354   public RestResponse pipeTo(OutputStream os) throws IOException {
355      pipe(asInputStream(), os);
356      return response;
357   }
358
359   /**
360    * Pipes the contents of the response to the specified writer.
361    *
362    * <h5 class='section'>Notes:</h5><ul>
363    * <li class='note'>
364    *    The writer is not automatically closed.
365    *    <li class='note'>
366    *       Once the reader is exhausted, it will automatically be closed.
367    *    <li class='note'>
368    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
369    *  <li class='note'>
370    *    This method can be called multiple times if {@link #cache()} has been called.
371    *  <li class='note'>
372    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
373    *    with an inner {@link IllegalStateException} to be thrown.
374    * </ul>
375    *
376    * @param w The writer to pipe the output to.
377    * @return This object.
378    * @throws IOException If an IO exception occurred.
379    */
380   public RestResponse pipeTo(Writer w) throws IOException {
381      return pipeTo(w, false);
382   }
383
384   /**
385    * Pipes the contents of the response to the specified writer.
386    *
387    * <h5 class='section'>Notes:</h5><ul>
388    * <li class='note'>
389    *    The writer is not automatically closed.
390    *    <li class='note'>
391    *       Once the reader is exhausted, it will automatically be closed.
392    *  <li class='note'>
393    *    This method can be called multiple times if {@link #cache()} has been called.
394    *  <li class='note'>
395    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
396    *    with an inner {@link IllegalStateException} to be thrown.
397    * </ul>
398    *
399    * @param w The writer to pipe the output to.
400    * @param charset
401    *    The charset to use for the reader.
402    *    <br>If <jk>null</jk>, <js>"UTF-8"</js> is used.
403    * @return This object.
404    * @throws IOException If an IO exception occurred.
405    */
406   public RestResponse pipeTo(Writer w, Charset charset) throws IOException {
407      return pipeTo(w, charset, false);
408   }
409
410   /**
411    * Pipes the contents of the response to the specified writer.
412    *
413    * <h5 class='section'>Notes:</h5><ul>
414    * <li class='note'>
415    *    The writer is not automatically closed.
416    *    <li class='note'>
417    *       Once the reader is exhausted, it will automatically be closed.
418    *    <li class='note'>
419    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
420    *  <li class='note'>
421    *    This method can be called multiple times if {@link #cache()} has been called.
422    *  <li class='note'>
423    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
424    *    with an inner {@link IllegalStateException} to be thrown.
425    * </ul>
426    *
427    * @param w The writer to write the output to.
428    * @param byLines Flush the writers after every line of output.
429    * @return This object.
430    * @throws IOException If an IO exception occurred.
431    */
432   public RestResponse pipeTo(Writer w, boolean byLines) throws IOException {
433      return pipeTo(w, null, byLines);
434   }
435
436   /**
437    * Pipes the contents of the response to the specified writer.
438    *
439    * <h5 class='section'>Notes:</h5><ul>
440    * <li class='note'>
441    *    The writer is not automatically closed.
442    *    <li class='note'>
443    *       Once the reader is exhausted, it will automatically be closed.
444    *  <li class='note'>
445    *    This method can be called multiple times if {@link #cache()} has been called.
446    *  <li class='note'>
447    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
448    *    with an inner {@link IllegalStateException} to be thrown.
449    * </ul>
450    *
451    * @param w The writer to pipe the output to.
452    * @param byLines Flush the writers after every line of output.
453    * @param charset
454    *    The charset to use for the reader.
455    *    <br>If <jk>null</jk>, <js>"UTF-8"</js> is used.
456    * @return This object.
457    * @throws IOException If an IO exception occurred.
458    */
459   public RestResponse pipeTo(Writer w, Charset charset, boolean byLines) throws IOException {
460      if (byLines)
461         pipeLines(asReader(charset), w);
462      else
463         pipe(asReader(charset), w);
464      return response;
465   }
466
467   //------------------------------------------------------------------------------------------------------------------
468   // Retrievers
469   //------------------------------------------------------------------------------------------------------------------
470
471   /**
472    * Parses HTTP body into the specified object type.
473    *
474    * <p>
475    * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
476    *
477    * <h5 class='section'>Examples:</h5>
478    * <p class='bjava'>
479    *    <jc>// Parse into a linked-list of strings.</jc>
480    *    List&lt;String&gt; <jv>list1</jv> = <jv>client</jv>
481    *       .get(<jsf>URI</jsf>)
482    *       .run()
483    *       .getContent().as(LinkedList.<jk>class</jk>, String.<jk>class</jk>);
484    *
485    *    <jc>// Parse into a linked-list of beans.</jc>
486    *    List&lt;MyBean&gt; <jv>list2</jv> = <jv>client</jv>
487    *       .get(<jsf>URI</jsf>)
488    *       .run()
489    *       .getContent().as(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
490    *
491    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
492    *    List&lt;List&lt;String&gt;&gt; <jv>list3</jv> = <jv>client</jv>
493    *       .get(<jsf>URI</jsf>)
494    *       .run()
495    *       .getContent().as(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
496    *
497    *    <jc>// Parse into a map of string keys/values.</jc>
498    *    Map&lt;String,String&gt; <jv>map1</jv> = <jv>client</jv>
499    *       .get(<jsf>URI</jsf>)
500    *       .run()
501    *       .getContent().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
502    *
503    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
504    *    Map&lt;String,List&lt;MyBean&gt;&gt; <jv>map2</jv> = <jv>client</jv>
505    *       .get(<jsf>URI</jsf>)
506    *       .run()
507    *       .getContent().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
508    * </p>
509    *
510    * <p>
511    * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
512    *
513    * <p>
514    * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
515    *
516    * <p>
517    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
518    *
519    * <h5 class='section'>Notes:</h5><ul>
520    *    <li class='note'>
521    *       Use the {@link #as(Class)} method instead if you don't need a parameterized map/collection.
522    *    <li class='note'>
523    *       You can also specify any of the following types:
524    *       <ul class='compact'>
525    *          <li>{@link ResponseContent}/{@link HttpEntity} - Returns access to this object.
526    *          <li>{@link Reader} - Returns access to the raw reader of the response.
527    *          <li>{@link InputStream} - Returns access to the raw input stream of the response.
528    *          <li>{@link HttpResource} - Response will be converted to an {@link BasicResource}.
529    *          <li>Any type that takes in an {@link HttpResponse} object.
530    *       </ul>
531    *    <li class='note'>
532    *    If {@link #cache()} or {@link RestResponse#cacheContent()} has been called, this method can be can be called multiple times and/or combined with
533    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
534    *    with an inner {@link IllegalStateException} will be thrown.
535    *    <li class='note'>
536    *       The input stream is automatically closed after this call.
537    * </ul>
538    *
539    * @param <T> The class type of the object to create.
540    * @param type
541    *    The object type to create.
542    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
543    * @param args
544    *    The type arguments of the class if it's a collection or map.
545    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
546    *    <br>Ignored if the main type is not a map or collection.
547    * @return The parsed object.
548    * @throws RestCallException
549    *    <ul>
550    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
551    *       <li>If a connection error occurred.
552    *    </ul>
553    * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
554    */
555   public <T> T as(Type type, Type...args) throws RestCallException {
556      return as(getClassMeta(type, args));
557   }
558
559   /**
560    * Same as {@link #as(Type,Type...)} except optimized for a non-parameterized class.
561    *
562    * <p>
563    * This is the preferred parse method for simple types since you don't need to cast the results.
564    *
565    * <h5 class='section'>Examples:</h5>
566    * <p class='bjava'>
567    *    <jc>// Parse into a string.</jc>
568    *    String <jv>string</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(String.<jk>class</jk>);
569    *
570    *    <jc>// Parse into a bean.</jc>
571    *    MyBean <jv>bean</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(MyBean.<jk>class</jk>);
572    *
573    *    <jc>// Parse into a bean array.</jc>
574    *    MyBean[] <jv>beanArray</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(MyBean[].<jk>class</jk>);
575    *
576    *    <jc>// Parse into a linked-list of objects.</jc>
577    *    List <jv>list</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(LinkedList.<jk>class</jk>);
578    *
579    *    <jc>// Parse into a map of object keys/values.</jc>
580    *    Map <jv>map</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(TreeMap.<jk>class</jk>);
581    * </p>
582    *
583    * <h5 class='section'>Notes:</h5><ul>
584    *    <li class='note'>
585    *       You can also specify any of the following types:
586    *       <ul class='compact'>
587    *          <li>{@link ResponseContent}/{@link HttpEntity} - Returns access to this object.
588    *          <li>{@link Reader} - Returns access to the raw reader of the response.
589    *          <li>{@link InputStream} - Returns access to the raw input stream of the response.
590    *          <li>{@link HttpResource} - Response will be converted to an {@link BasicResource}.
591    *          <li>Any type that takes in an {@link HttpResponse} object.
592    *       </ul>
593    *    <li class='note'>
594    *    If {@link #cache()} or {@link RestResponse#cacheContent()} has been called, this method can be can be called multiple times and/or combined with
595    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
596    *    with an inner {@link IllegalStateException} will be thrown.
597    *    <li class='note'>
598    *       The input stream is automatically closed after this call.
599    * </ul>
600    *
601    * @param <T>
602    *    The class type of the object being created.
603    *    See {@link #as(Type,Type...)} for details.
604    * @param type The object type to create.
605    * @return The parsed object.
606    * @throws RestCallException
607    *    If the input contains a syntax error or is malformed, or is not valid for the specified type, or if a connection
608    *    error occurred.
609    */
610   public <T> T as(Class<T> type) throws RestCallException {
611      return as(getClassMeta(type));
612   }
613
614   /**
615    * Same as {@link #as(Class)} except allows you to predefine complex data types using the {@link ClassMeta} API.
616    *
617    * <h5 class='section'>Examples:</h5>
618    * <p class='bjava'>
619    *    BeanContext <jv>beanContext</jv> = BeanContext.<jsf>DEFAULT</jsf>;
620    *
621    *    <jc>// Parse into a linked-list of strings.</jc>
622    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm1</jv> = <jv>beanContext</jv>.getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);
623    *    List&lt;String&gt; <jv>list1</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(<jv>cm1</jv>);
624    *
625    *    <jc>// Parse into a linked-list of beans.</jc>
626    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm2</jv> = <jv>beanContext</jv>.getClassMeta(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
627    *    List&lt;MyBean&gt; <jv>list2</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(<jv>cm2</jv>);
628    *
629    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
630    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm3</jv> = <jv>beanContext</jv>.getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
631    *    List&lt;List&lt;String&gt;&gt; <jv>list3</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(<jv>cm3</jv>);
632    *
633    *    <jc>// Parse into a map of string keys/values.</jc>
634    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm4</jv> = <jv>beanContext</jv>.getClassMeta(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
635    *    Map&lt;String,String&gt; <jv>map4</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(<jv>cm4</jv>);
636    *
637    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
638    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm5</jv> = <jv>beanContext</jv>.getClassMeta(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
639    *    Map&lt;String,List&lt;MyBean&gt;&gt; <jv>map5</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().as(<jv>cm5</jv>);
640    * </p>
641    *
642    * <h5 class='section'>Notes:</h5><ul>
643    *    <li class='note'>
644    *    If {@link #cache()} or {@link RestResponse#cacheContent()} has been called, this method can be can be called multiple times and/or combined with
645    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
646    *    with an inner {@link IllegalStateException} will be thrown.
647    *    <li class='note'>
648    *       The input stream is automatically closed after this call.
649    * </ul>
650    *
651    * @param <T> The class type of the object to create.
652    * @param type The object type to create.
653    * @return The parsed object.
654    * @throws RestCallException
655    *    <ul>
656    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
657    *       <li>If a connection error occurred.
658    *    </ul>
659    * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
660    */
661   @SuppressWarnings("unchecked")
662   public <T> T as(ClassMeta<T> type) throws RestCallException {
663      try {
664         if (type.is(ResponseContent.class) || type.is(HttpEntity.class))
665            return (T)this;
666
667         if (type.is(Reader.class))
668            return (T)asReader();
669
670         if (type.is(InputStream.class))
671            return (T)asInputStream();
672
673         if (type.is(HttpResponse.class))
674            return (T)response;
675
676         if (type.is(HttpResource.class))
677            type = (ClassMeta<T>)getClassMeta(BasicResource.class);
678
679         ConstructorInfo ci = type.getInfo().getPublicConstructor(x -> x.hasParamTypes(HttpResponse.class));
680         if (ci != null) {
681            try {
682               return (T)ci.invoke(response);
683            } catch (ExecutableException e) {
684               throw asRuntimeException(e);
685            }
686         }
687
688         String ct = firstNonEmpty(response.getHeader("Content-Type").orElse("text/plain"));
689
690         if (parser == null)
691            parser = client.getMatchingParser(ct);
692
693         MediaType mt = MediaType.of(ct);
694
695         if (parser == null || (mt.toString().contains("text/plain") && ! parser.canHandle(ct))) {
696            if (type.hasStringMutater())
697               return type.getStringMutater().mutate(asString());
698         }
699
700         if (parser != null) {
701            try (Closeable in = parser.isReaderParser() ? asReader() : asInputStream()) {
702
703               T t = parser
704                  .createSession()
705                  .properties(JsonMap.create().inner(request.getSessionProperties()))
706                  .locale(response.getLocale())
707                  .mediaType(mt)
708                  .schema(schema)
709                  .build()
710                  .parse(in, type);
711
712               // Some HTTP responses have no body, so try to create these beans if they've got no-arg constructors.
713               if (t == null && ! type.is(String.class)) {
714                  ConstructorInfo c = type.getInfo().getPublicConstructor(x -> x.hasNoParams());
715                  if (c != null) {
716                     try {
717                        return c.<T>invoke();
718                     } catch (ExecutableException e) {
719                        throw new ParseException(e);
720                     }
721                  }
722               }
723
724               return t;
725            }
726         }
727
728         if (type.hasReaderMutater())
729            return type.getReaderMutater().mutate(asReader());
730
731         if (type.hasInputStreamMutater())
732            return type.getInputStreamMutater().mutate(asInputStream());
733
734         ct = response.getStringHeader("Content-Type").orElse(null);
735
736         if (ct == null && client.hasParsers())
737            throw new ParseException("Content-Type not specified in response header.  Cannot find appropriate parser.");
738
739         throw new ParseException("Unsupported media-type in request header ''Content-Type'': ''{0}''", ct);
740
741      } catch (ParseException | IOException e) {
742         response.close();
743         throw new RestCallException(response, e, "Could not parse response body.");
744      }
745   }
746
747   /**
748    * Same as {@link #as(Class)} but allows you to run the call asynchronously.
749    *
750    * <h5 class='section'>Notes:</h5><ul>
751    *    <li class='note'>
752    *    If {@link #cache()} or {@link RestResponse#cacheContent()} has been called, this method can be can be called multiple times and/or combined with
753    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
754    *    with an inner {@link IllegalStateException} will be thrown.
755    *    <li class='note'>
756    *       The input stream is automatically closed after the execution of the future.
757    * </ul>
758    *
759    * @param <T> The class type of the object being created.
760    * @param type The object type to create.
761    * @return The future object.
762    * @throws RestCallException If the executor service was not defined.
763    * @see
764    *    RestClient.Builder#executorService(ExecutorService, boolean) for defining the executor service for creating
765    *    {@link Future Futures}.
766    */
767   public <T> Future<T> asFuture(final Class<T> type) throws RestCallException {
768      return client.getExecutorService().submit(
769         new Callable<T>() {
770            @Override /* Callable */
771            public T call() throws Exception {
772               return as(type);
773            }
774         }
775      );
776   }
777
778   /**
779    * Same as {@link #as(ClassMeta)} but allows you to run the call asynchronously.
780    *
781    * <h5 class='section'>Notes:</h5><ul>
782    *    <li class='note'>
783    *    If {@link #cache()} or {@link RestResponse#cacheContent()} has been called, this method can be can be called multiple times and/or combined with
784    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
785    *    with an inner {@link IllegalStateException} will be thrown.
786    *    <li class='note'>
787    *       The input stream is automatically closed after the execution of the future.
788    * </ul>
789    *
790    * @param <T>
791    *    The class type of the object being created.
792    *    See {@link #as(Type, Type...)} for details.
793    * @param type The object type to create.
794    * @return The future object.
795    * @throws RestCallException If the executor service was not defined.
796    * @see
797    *    RestClient.Builder#executorService(ExecutorService, boolean) for defining the executor service for creating
798    *    {@link Future Futures}.
799    */
800   public <T> Future<T> asFuture(final ClassMeta<T> type) throws RestCallException {
801      return client.getExecutorService().submit(
802         new Callable<T>() {
803            @Override /* Callable */
804            public T call() throws Exception {
805               return as(type);
806            }
807         }
808      );
809   }
810
811   /**
812    * Same as {@link #as(Type,Type...)} but allows you to run the call asynchronously.
813    *
814    * <h5 class='section'>Notes:</h5><ul>
815    *    <li class='note'>
816    *    If {@link #cache()} or {@link RestResponse#cacheContent()} has been called, this method can be can be called multiple times and/or combined with
817    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
818    *    with an inner {@link IllegalStateException} will be thrown.
819    *    <li class='note'>
820    *       The input stream is automatically closed after the execution of the future.
821    * </ul>
822    *
823    * @param <T>
824    *    The class type of the object being created.
825    *    See {@link #as(Type, Type...)} for details.
826    * @param type
827    *    The object type to create.
828    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
829    * @param args
830    *    The type arguments of the class if it's a collection or map.
831    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
832    *    <br>Ignored if the main type is not a map or collection.
833    * @return The future object.
834    * @throws RestCallException If the executor service was not defined.
835    * @see
836    *    RestClient.Builder#executorService(ExecutorService, boolean) for defining the executor service for creating
837    *    {@link Future Futures}.
838    */
839   public <T> Future<T> asFuture(final Type type, final Type...args) throws RestCallException {
840      return client.getExecutorService().submit(
841         new Callable<T>() {
842            @Override /* Callable */
843            public T call() throws Exception {
844               return as(type, args);
845            }
846         }
847      );
848   }
849
850   /**
851    * Returns the contents of this body as a string.
852    *
853    * <h5 class='section'>Notes:</h5><ul>
854    *    <li class='note'>
855    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
856    *  <li class='note'>
857    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
858    *    <li class='note'>
859    *       The input stream is automatically closed after this call.
860    * </ul>
861    *
862    * @return The response as a string.
863    * @throws RestCallException
864    *    <ul>
865    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
866    *       <li>If a connection error occurred.
867    *    </ul>
868    */
869   public String asString() throws RestCallException {
870      cache();
871      try (Reader r = asReader()) {
872         return read(r);
873      } catch (IOException e) {
874         response.close();
875         throw new RestCallException(response, e, "Could not read response body.");
876      }
877   }
878
879   /**
880    * Same as {@link #asString()} but allows you to run the call asynchronously.
881    *
882    * <h5 class='section'>Notes:</h5><ul>
883    *    <li class='note'>
884    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
885    *  <li class='note'>
886    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
887    *    <li class='note'>
888    *       The input stream is automatically closed after this call.
889    * </ul>
890    *
891    * @return The future object.
892    * @throws RestCallException If the executor service was not defined.
893    * @see
894    *    RestClient.Builder#executorService(ExecutorService, boolean) for defining the executor service for creating
895    *    {@link Future Futures}.
896    */
897   public Future<String> asStringFuture() throws RestCallException {
898      return client.getExecutorService().submit(
899         new Callable<String>() {
900            @Override /* Callable */
901            public String call() throws Exception {
902               return asString();
903            }
904         }
905      );
906   }
907
908   /**
909    * Same as {@link #asString()} but truncates the string to the specified length.
910    *
911    * <p>
912    * If truncation occurs, the string will be suffixed with <js>"..."</js>.
913    *
914    * @param length The max length of the returned string.
915    * @return The truncated string.
916    * @throws RestCallException If a problem occurred trying to read from the reader.
917    */
918   public String asAbbreviatedString(int length) throws RestCallException {
919      return StringUtils.abbreviate(asString(), length);
920   }
921
922   /**
923    * Returns the HTTP body content as a simple hexadecimal character string.
924    *
925    * <h5 class='section'>Example:</h5>
926    * <p class='bcode'>
927    *    0123456789ABCDEF
928    * </p>
929    *
930    * @return The incoming input from the connection as a plain string.
931    * @throws RestCallException If a problem occurred trying to read from the reader.
932    */
933   public String asHex() throws RestCallException {
934      return toHex(asBytes());
935   }
936
937   /**
938    * Returns the HTTP body content as a simple space-delimited hexadecimal character string.
939    *
940    * <h5 class='section'>Example:</h5>
941    * <p class='bcode'>
942    *    01 23 45 67 89 AB CD EF
943    * </p>
944    *
945    * @return The incoming input from the connection as a plain string.
946    * @throws RestCallException If a problem occurred trying to read from the reader.
947    */
948   public String asSpacedHex() throws RestCallException {
949      return toSpacedHex(asBytes());
950   }
951
952   /**
953    * Parses the output from the body into the specified type and then wraps that in a {@link ObjectRest}.
954    *
955    * <p>
956    * Useful if you want to quickly retrieve a single value from inside of a larger JSON document.
957    *
958    * @param innerType The class type of the POJO being wrapped.
959    * @return The parsed output wrapped in a {@link ObjectRest}.
960    * @throws RestCallException
961    *    <ul>
962    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
963    *       <li>If a connection error occurred.
964    *    </ul>
965    */
966   public ObjectRest asObjectRest(Class<?> innerType) throws RestCallException {
967      return new ObjectRest(as(innerType));
968   }
969
970   /**
971    * Converts the output from the connection into an {@link JsonMap} and then wraps that in a {@link ObjectRest}.
972    *
973    * <p>
974    * Useful if you want to quickly retrieve a single value from inside of a larger JSON document.
975    *
976    * @return The parsed output wrapped in a {@link ObjectRest}.
977    * @throws RestCallException
978    *    <ul>
979    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
980    *       <li>If a connection error occurred.
981    *    </ul>
982    */
983   public ObjectRest asObjectRest() throws RestCallException {
984      return asObjectRest(JsonMap.class);
985   }
986
987   /**
988    * Converts the contents of the response body to a string and then matches the specified pattern against it.
989    *
990    * <h5 class='section'>Example:</h5>
991    * <p class='bjava'>
992    *    <jc>// Parse response using a regular expression.</jc>
993    *    Matcher <jv>matcher</jv> = <jv>client</jv>
994    *       .get(<jsf>URI</jsf>)
995    *       .run()
996    *       .getContent().asMatcher(Pattern.<jsm>compile</jsm>(<js>"foo=(.*)"</js>));
997    *
998    *    <jk>if</jk> (<jv>matcher</jv>.matches()) {
999    *       String <jv>foo</jv> = <jv>matcher</jv>.group(1);
1000    *    }
1001    * </p>
1002    *
1003    * <h5 class='section'>Notes:</h5><ul>
1004    *    <li class='note'>
1005    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1006    *  <li class='note'>
1007    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
1008    *    <li class='note'>
1009    *       The input stream is automatically closed after this call.
1010    * </ul>
1011    *
1012    * @param pattern The regular expression pattern to match.
1013    * @return The matcher.
1014    * @throws RestCallException If a connection error occurred.
1015    */
1016   public Matcher asMatcher(Pattern pattern) throws RestCallException {
1017      return pattern.matcher(asString());
1018   }
1019
1020   /**
1021    * Converts the contents of the response body to a string and then matches the specified pattern against it.
1022    *
1023    * <h5 class='section'>Example:</h5>
1024    * <p class='bjava'>
1025    *    <jc>// Parse response using a regular expression.</jc>
1026    *    Matcher <jv>matcher</jv> = <jv>client</jv>
1027    *       .get(<jsf>URI</jsf>)
1028    *       .run()
1029    *       .getContent().asMatcher(<js>"foo=(.*)"</js>);
1030    *
1031    *    <jk>if</jk> (<jv>matcher</jv>.matches()) {
1032    *       String <jv>foo</jv> = <jv>matcher</jv>.group(1);
1033    *    }
1034    * </p>
1035    *
1036    *
1037    * <h5 class='section'>Notes:</h5><ul>
1038    *    <li class='note'>
1039    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1040    *  <li class='note'>
1041    *    If {@link #cache()} or {@link RestResponse#cacheContent()} has been called, this method can be can be called multiple times and/or combined with
1042    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1043    *    with an inner {@link IllegalStateException} will be thrown.
1044    *    <li class='note'>
1045    *       The input stream is automatically closed after this call.
1046    * </ul>
1047    *
1048    * @param regex The regular expression pattern to match.
1049    * @return The matcher.
1050    * @throws RestCallException If a connection error occurred.
1051    */
1052   public Matcher asMatcher(String regex) throws RestCallException {
1053      return asMatcher(regex, 0);
1054   }
1055
1056   /**
1057    * Converts the contents of the response body to a string and then matches the specified pattern against it.
1058    *
1059    * <h5 class='section'>Example:</h5>
1060    * <p class='bjava'>
1061    *    <jc>// Parse response using a regular expression.</jc>
1062    *    Matcher <jv>matcher</jv> = <jv>client</jv>
1063    *       .get(<jsf>URI</jsf>)
1064    *       .run()
1065    *       .getContent().asMatcher(<js>"foo=(.*)"</js>, <jsf>MULTILINE</jsf> &amp; <jsf>CASE_INSENSITIVE</jsf>);
1066    *
1067    *    <jk>if</jk> (<jv>matcher</jv>.matches()) {
1068    *       String <jv>foo</jv> = <jv>matcher</jv>.group(1);
1069    *    }
1070    * </p>
1071    *
1072    *
1073    * <h5 class='section'>Notes:</h5><ul>
1074    *    <li class='note'>
1075    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1076    *  <li class='note'>
1077    *    If {@link #cache()} or {@link RestResponse#cacheContent()} has been called, this method can be can be called multiple times and/or combined with
1078    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1079    *    with an inner {@link IllegalStateException} will be thrown.
1080    *    <li class='note'>
1081    *       The input stream is automatically closed after this call.
1082    * </ul>
1083    *
1084    * @param regex The regular expression pattern to match.
1085    * @param flags Pattern match flags.  See {@link Pattern#compile(String, int)}.
1086    * @return The matcher.
1087    * @throws RestCallException If a connection error occurred.
1088    */
1089   public Matcher asMatcher(String regex, int flags) throws RestCallException {
1090      return asMatcher(Pattern.compile(regex, flags));
1091   }
1092
1093   //------------------------------------------------------------------------------------------------------------------
1094   // Assertions
1095   //------------------------------------------------------------------------------------------------------------------
1096
1097   /**
1098    * Provides the ability to perform fluent-style assertions on this response body.
1099    *
1100    * <p>
1101    * This method is called directly from the {@link RestResponse#assertContent()} method to instantiate a fluent assertions object.
1102    *
1103    * <h5 class='section'>Examples:</h5>
1104    * <p class='bjava'>
1105    *    <jc>// Validates the response body equals the text "OK".</jc>
1106    *    <jv>client</jv>
1107    *       .get(<jsf>URI</jsf>)
1108    *       .run()
1109    *       .getContent().assertValue().equals(<js>"OK"</js>);
1110    *
1111    *    <jc>// Validates the response body contains the text "OK".</jc>
1112    *    <jv>client</jv>
1113    *       .get(<jsf>URI</jsf>)
1114    *       .run()
1115    *       .getContent().assertValue().contains(<js>"OK"</js>);
1116    *
1117    *    <jc>// Validates the response body passes a predicate test.</jc>
1118    *    <jv>client</jv>
1119    *       .get(<jsf>URI</jsf>)
1120    *       .run()
1121    *       .getContent().assertValue().is(<jv>x</jv> -&gt; <jv>x</jv>.contains(<js>"OK"</js>));
1122    *
1123    *    <jc>// Validates the response body matches a regular expression.</jc>
1124    *    <jv>client</jv>
1125    *       .get(<jsf>URI</jsf>)
1126    *       .run()
1127    *       .getContent().assertValue().isPattern(<js>".*OK.*"</js>);
1128    *
1129    *    <jc>// Validates the response body matches a regular expression using regex flags.</jc>
1130    *    <jv>client</jv>
1131    *       .get(<jsf>URI</jsf>)
1132    *       .run()
1133    *       .getContent().assertValue().isPattern(<js>".*OK.*"</js>,  <jsf>MULTILINE</jsf> &amp; <jsf>CASE_INSENSITIVE</jsf>);
1134    *
1135    *    <jc>// Validates the response body matches a regular expression in the form of an existing Pattern.</jc>
1136    *    Pattern <jv>pattern</jv> = Pattern.<jsm>compile</jsm>(<js>".*OK.*"</js>);
1137    *    <jv>client</jv>
1138    *       .get(<jsf>URI</jsf>)
1139    *       .run()
1140    *       .getContent().assertValue().isPattern(<jv>pattern</jv>);
1141    * </p>
1142    *
1143    * <p>
1144    * The assertion test returns the original response object allowing you to chain multiple requests like so:
1145    * <p class='bjava'>
1146    *    <jc>// Validates the response body matches a regular expression.</jc>
1147    *    MyBean <jv>bean</jv> = <jv>client</jv>
1148    *       .get(<jsf>URI</jsf>)
1149    *       .run()
1150    *       .getContent().assertValue().isPattern(<js>".*OK.*"</js>);
1151    *       .getContent().assertValue().isNotPattern(<js>".*ERROR.*"</js>)
1152    *       .getContent().as(MyBean.<jk>class</jk>);
1153    * </p>
1154    *
1155    * <h5 class='section'>Notes:</h5><ul>
1156    *    <li class='note'>
1157    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1158    *  <li class='note'>
1159    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
1160    *    <li class='note'>
1161    *       The input stream is automatically closed after this call.
1162    * </ul>
1163    *
1164    * @return A new fluent assertion object.
1165    */
1166   public FluentResponseBodyAssertion<ResponseContent> assertValue() {
1167      return new FluentResponseBodyAssertion<>(this, this);
1168   }
1169
1170   /**
1171    * Shortcut for calling <c>assertValue().asString()</c>.
1172    *
1173    * @return A new fluent assertion.
1174    */
1175   public FluentStringAssertion<ResponseContent> assertString() {
1176      return new FluentResponseBodyAssertion<>(this, this).asString();
1177   }
1178
1179   /**
1180    * Shortcut for calling <c>assertValue().asBytes()</c>.
1181    *
1182    * @return A new fluent assertion.
1183    */
1184   public FluentByteArrayAssertion<ResponseContent> assertBytes() {
1185      return new FluentResponseBodyAssertion<>(this, this).asBytes();
1186   }
1187
1188   /**
1189    * Shortcut for calling <c>assertValue().as(<jv>type</jv>)</c>.
1190    *
1191    * @param <T> The object type to create.
1192    * @param type The object type to create.
1193    * @return A new fluent assertion.
1194    */
1195   public <T> FluentAnyAssertion<T,ResponseContent> assertObject(Class<T> type) {
1196      return new FluentResponseBodyAssertion<>(this, this).as(type);
1197   }
1198
1199   /**
1200    * Shortcut for calling <c>assertValue().as(<jv>type</jv>, <jv>args</jv>)</c>.
1201    *
1202    * @param <T> The object type to create.
1203    * @param type The object type to create.
1204    * @param args Optional type arguments.
1205    * @return A new fluent assertion.
1206    */
1207   public <T> FluentAnyAssertion<Object,ResponseContent> assertObject(Type type, Type...args) {
1208      return new FluentResponseBodyAssertion<>(this, this).as(type, args);
1209   }
1210
1211   /**
1212    * Returns the response that created this object.
1213    *
1214    * @return The response that created this object.
1215    */
1216   public RestResponse response() {
1217      return response;
1218   }
1219
1220   //------------------------------------------------------------------------------------------------------------------
1221   // HttpEntity passthrough methods.
1222   //------------------------------------------------------------------------------------------------------------------
1223
1224   /**
1225    * Tells if the entity is capable of producing its data more than once.
1226    *
1227    * <p>
1228    * A repeatable entity's {@link #getContent()} and {@link #writeTo(OutputStream)} methods can be called more than
1229    * once whereas a non-repeatable entity's can not.
1230    *
1231    * <h5 class='section'>Notes:</h5><ul>
1232    * <li class='note'>This method always returns <jk>true</jk> if the response body is cached (see {@link #cache()}).
1233    * </ul>
1234    *
1235    * @return <jk>true</jk> if the entity is repeatable, <jk>false</jk> otherwise.
1236    */
1237   @Override /* HttpEntity */
1238   public boolean isRepeatable() {
1239      return cached || entity.isRepeatable();
1240   }
1241
1242   /**
1243    * Tells about chunked encoding for this entity.
1244    *
1245    * <p>
1246    * The primary purpose of this method is to indicate whether chunked encoding should be used when the entity is sent.
1247    * <br>For entities that are received, it can also indicate whether the entity was received with chunked encoding.
1248    *
1249    * <p>
1250    * The behavior of wrapping entities is implementation dependent, but should respect the primary purpose.
1251    *
1252    * @return <jk>true</jk> if chunked encoding is preferred for this entity, or <jk>false</jk> if it is not.
1253    */
1254   @Override /* HttpEntity */
1255   public boolean isChunked() {
1256      return entity.isChunked();
1257   }
1258
1259   /**
1260    * Tells the length of the content, if known.
1261    *
1262    * @return
1263    *    The number of bytes of the content, or a negative number if unknown.
1264    *    <br>If the content length is known but exceeds {@link Long#MAX_VALUE}, a negative number is returned.
1265    */
1266   @Override /* HttpEntity */
1267   public long getContentLength() {
1268      return body != null ? body.length : entity.getContentLength();
1269   }
1270
1271   /**
1272    * Obtains the <c>Content-Type</c> header, if known.
1273    *
1274    * <p>
1275    * This is the header that should be used when sending the entity, or the one that was received with the entity.
1276    * It can include a charset attribute.
1277    *
1278    * @return The <c>Content-Type</c> header for this entity, or <jk>null</jk> if the content type is unknown.
1279    */
1280   @Override /* HttpEntity */
1281   public ResponseHeader getContentType() {
1282      return new ResponseHeader("Content-Type", request, response, entity.getContentType());
1283   }
1284
1285   /**
1286    * Obtains the Content-Encoding header, if known.
1287    *
1288    * <p>
1289    * This is the header that should be used when sending the entity, or the one that was received with the entity.
1290    * <br>Wrapping entities that modify the content encoding should adjust this header accordingly.
1291    *
1292    * @return The <c>Content-Encoding</c> header for this entity, or <jk>null</jk> if the content encoding is unknown.
1293    */
1294   @Override /* HttpEntity */
1295   public ResponseHeader getContentEncoding() {
1296      return new ResponseHeader("Content-Encoding", request, response, entity.getContentEncoding());
1297   }
1298
1299   /**
1300    * Returns a content stream of the entity.
1301    *
1302    * <h5 class='section'>Notes:</h5><ul>
1303    *    <li class='note'>This method is equivalent to {@link #asInputStream()} which is the preferred method for fluent-style coding.
1304    *    <li class='note'>This input stream will auto-close once the end of stream has been reached.
1305    *    <li class='note'>It is up to the caller to properly close this stream if not fully consumed.
1306    *    <li class='note'>This method can be called multiple times if the entity is repeatable or the cache flag is set on this object.
1307    *    <li class='note'>Calling this method multiple times on a non-repeatable or cached body will throw a {@link IllegalStateException}.
1308    *       Note that this is different from the HttpClient specs for this method.
1309    * </ul>
1310    *
1311    * @return Content stream of the entity.
1312    */
1313   @Override /* HttpEntity */
1314   public InputStream getContent() throws IOException, UnsupportedOperationException {
1315      return asInputStream();
1316   }
1317
1318   /**
1319    * Writes the entity content out to the output stream.
1320    *
1321    * <h5 class='section'>Notes:</h5><ul>
1322    *    <li class='note'>This method is equivalent to {@link #pipeTo(OutputStream)} which is the preferred method for fluent-style coding.
1323    * </ul>
1324    *
1325    * @param outstream The output stream to write entity content to.
1326    */
1327   @Override /* HttpEntity */
1328   public void writeTo(OutputStream outstream) throws IOException {
1329      pipeTo(outstream);
1330   }
1331
1332   /**
1333    * Tells whether this entity depends on an underlying stream.
1334    *
1335    * <h5 class='section'>Notes:</h5><ul>
1336    * <li class='note'>This method always returns <jk>false</jk> if the response body is cached (see {@link #cache()}.
1337    * </ul>
1338    *
1339    * @return <jk>true</jk> if the entity content is streamed, <jk>false</jk> otherwise.
1340    */
1341   @Override /* HttpEntity */
1342   public boolean isStreaming() {
1343      return cached ? false : entity.isStreaming();
1344   }
1345
1346   /**
1347    * This method is called to indicate that the content of this entity is no longer required.
1348    *
1349    * <p>
1350    * This method is of particular importance for entities being received from a connection.
1351    * <br>The entity needs to be consumed completely in order to re-use the connection with keep-alive.
1352    *
1353    * @throws IOException If an I/O error occurs.
1354    * @deprecated Use standard java convention to ensure resource deallocation by calling {@link InputStream#close()} on
1355    * the input stream returned by {@link #getContent()}
1356    */
1357   @Override /* HttpEntity */
1358   @Deprecated
1359   public void consumeContent() throws IOException {
1360      entity.consumeContent();
1361   }
1362
1363   //------------------------------------------------------------------------------------------------------------------
1364   // Utility methods
1365   //------------------------------------------------------------------------------------------------------------------
1366
1367   private BeanContext getBeanContext() {
1368      return parser == null ? BeanContext.DEFAULT : parser.getBeanContext();
1369   }
1370
1371   private <T> ClassMeta<T> getClassMeta(Class<T> c) {
1372      return getBeanContext().getClassMeta(c);
1373   }
1374
1375   private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
1376      return getBeanContext().getClassMeta(type, args);
1377   }
1378
1379   @Override
1380   public String toString() {
1381      try {
1382         return asString();
1383      } catch (RestCallException e) {
1384         return e.getLocalizedMessage();
1385      }
1386   }
1387}