001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.client2;
014
015import static org.apache.juneau.internal.IOUtils.*;
016import static org.apache.juneau.internal.StringUtils.*;
017
018import java.io.*;
019import java.lang.reflect.*;
020import java.nio.charset.*;
021import java.util.concurrent.*;
022import java.util.regex.*;
023
024import org.apache.http.*;
025import org.apache.http.conn.*;
026import org.apache.juneau.*;
027import org.apache.juneau.assertions.*;
028import org.apache.juneau.collections.*;
029import org.apache.juneau.http.*;
030import org.apache.juneau.httppart.*;
031import org.apache.juneau.internal.*;
032import org.apache.juneau.oapi.*;
033import org.apache.juneau.parser.*;
034import org.apache.juneau.parser.ParseException;
035import org.apache.juneau.reflect.*;
036import org.apache.juneau.utils.*;
037
038/**
039 * Represents the body of an HTTP response.
040 *
041 * <p>
042 * An extension of an HttpClient {@link HttpEntity} that provides various support for converting the body to POJOs and
043 * other convenience methods.
044 *
045 * <ul class='seealso'>
046 *    <li class='jc'>{@link RestClient}
047 *    <li class='link'>{@doc juneau-rest-client}
048 * </ul>
049 */
050public class RestResponseBody implements HttpEntity {
051
052   private static final HttpEntity NULL_ENTITY = new HttpEntity() {
053
054      @Override
055      public boolean isRepeatable() {
056         return false;
057      }
058
059      @Override
060      public boolean isChunked() {
061         return false;
062      }
063
064      @Override
065      public long getContentLength() {
066         return -1;
067      }
068
069      @Override
070      public Header getContentType() {
071         return RestResponseHeader.NULL_HEADER;
072      }
073
074      @Override
075      public Header getContentEncoding() {
076         return RestResponseHeader.NULL_HEADER;
077      }
078
079      @Override
080      public InputStream getContent() throws IOException, UnsupportedOperationException {
081         return new ByteArrayInputStream(new byte[0]);
082      }
083
084      @Override
085      public void writeTo(OutputStream outstream) throws IOException {}
086
087      @Override
088      public boolean isStreaming() {
089         return false;
090      }
091
092      @Override
093      public void consumeContent() throws IOException {}
094   };
095
096   private final RestClient client;
097   final RestRequest request;
098   final RestResponse response;
099   private final HttpEntity entity;
100   private HttpPartSchema schema;
101   private Parser parser;
102   private byte[] cache;
103   private boolean cached;
104   boolean isConsumed;
105
106   /**
107    * Constructor.
108    *
109    * @param client The client used to build this request.
110    * @param request The request object.
111    * @param response The response object.
112    * @param parser The parser to use to consume the body.  Can be <jk>null</jk>.
113    */
114   public RestResponseBody(RestClient client, RestRequest request, RestResponse response, Parser parser) {
115      this.client = client;
116      this.request = request;
117      this.response = response;
118      this.parser = parser;
119      this.entity = ObjectUtils.firstNonNull(response.asHttpResponse().getEntity(), NULL_ENTITY);
120   }
121
122   //------------------------------------------------------------------------------------------------------------------
123   // Setters
124   //------------------------------------------------------------------------------------------------------------------
125
126   /**
127    * Specifies the parser to use for this body.
128    *
129    * <p>
130    * If not specified, uses the parser defined on the client set via {@link RestClientBuilder#parser(Class)}.
131    *
132    * @param value
133    *    The new part parser to use for this body.
134    * @return This object (for method chaining).
135    */
136   public RestResponseBody parser(Parser value) {
137      this.parser = value;
138      return this;
139   }
140
141   /**
142    * Specifies the schema for this body.
143    *
144    * <p>
145    * Used by schema-based parsers such as {@link OpenApiParser}.
146    *
147    * @param value The schema.
148    * @return This object (for method chaining).
149    */
150   public RestResponseBody schema(HttpPartSchema value) {
151      this.schema = value;
152      return this;
153   }
154
155   /**
156    * Causes the contents of the response body to be stored so that it can be repeatedly read.
157    *
158    * <p>
159    * Calling this method allows methods that read the response body to be called multiple times.
160    *
161    * <ul class='notes'>
162    *    <li>
163    *       Multiple calls to this method are ignored.
164    * </ul>
165    *
166    * @return This object (for method chaining).
167    */
168   public RestResponseBody cache() {
169      this.cached = true;
170      return this;
171   }
172
173   //------------------------------------------------------------------------------------------------------------------
174   // Raw streams
175   //------------------------------------------------------------------------------------------------------------------
176
177   /**
178    * Returns the HTTP response message body as an input stream.
179    *
180    * <ul class='notes'>
181    *    <li>
182    *       Once this input stream is exhausted, it will automatically be closed.
183    *  <li>
184    *    This method can be called multiple times if {@link #cache()} has been called.
185    *  <li>
186    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
187    *    with an inner {@link IllegalStateException} to be thrown.
188    * </ul>
189    *
190    * @return
191    *    The HTTP response message body input stream, never <jk>null</jk>.
192    *    <br>For responses without a body(e.g. HTTP 204), returns an empty stream.
193    * @throws IOException If a stream or illegal state exception was thrown.
194    */
195   public InputStream asInputStream() throws IOException {
196      try {
197         if (cache != null)
198            return new ByteArrayInputStream(cache);
199
200         if (cached) {
201            cache = IOUtils.readBytes(entity.getContent());
202            response.close();
203            return new ByteArrayInputStream(cache);
204         }
205
206         if (isConsumed && ! entity.isRepeatable())
207            throw new IllegalStateException("Method cannot be called.  Response has already been consumed.  Consider using the RestResponse.cacheBody() method.");
208
209         HttpEntity e = response.asHttpResponse().getEntity();
210         InputStream is = e == null ? new ByteArrayInputStream(new byte[0]) : e.getContent();
211
212         is = new EofSensorInputStream(is, new EofSensorWatcher() {
213            @Override
214            public boolean eofDetected(InputStream wrapped) throws IOException {
215               try {
216                  response.close();
217               } catch (RestCallException e) {}
218               return true;
219            }
220            @Override
221            public boolean streamClosed(InputStream wrapped) throws IOException {
222               try {
223                  response.close();
224               } catch (RestCallException e) {}
225               return true;
226            }
227            @Override
228            public boolean streamAbort(InputStream wrapped) throws IOException {
229               try {
230                  response.close();
231               } catch (RestCallException e) {}
232               return true;
233            }
234         });
235
236         isConsumed = true;
237
238         return is;
239      } catch (UnsupportedOperationException | RestCallException e) {
240         throw new IOException(e);
241      }
242   }
243
244   /**
245    * Returns the HTTP response message body as a reader based on the charset on the <code>Content-Type</code> response header.
246    *
247    * <ul class='notes'>
248    *    <li>
249    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
250    *    <li>
251    *       Once this input stream is exhausted, it will automatically be closed.
252    *  <li>
253    *    This method can be called multiple times if {@link #cache()} has been called.
254    *  <li>
255    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
256    *    with an inner {@link IllegalStateException} to be thrown.
257    * </ul>
258    *
259    * @return
260    *    The HTTP response message body reader, never <jk>null</jk>.
261    *    <br>For responses without a body(e.g. HTTP 204), returns an empty reader.
262    * @throws IOException If an exception occurred.
263    */
264   public Reader asReader() throws IOException {
265
266      // Figure out what the charset of the response is.
267      String cs = null;
268      String ct = getContentType().asString();
269
270      // First look for "charset=" in Content-Type header of response.
271      if (ct != null)
272         if (ct.contains("charset="))
273            cs = ct.substring(ct.indexOf("charset=")+8).trim();
274
275      return asReader(cs == null ? IOUtils.UTF8 : Charset.forName(cs));
276   }
277
278   /**
279    * Returns the HTTP response message body as a reader using the specified charset.
280    *
281    * <ul class='notes'>
282    *    <li>
283    *       Once this input stream is exhausted, it will automatically be closed.
284    *  <li>
285    *    This method can be called multiple times if {@link #cache()} has been called.
286    *  <li>
287    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
288    *    with an inner {@link IllegalStateException} to be thrown.
289    * </ul>
290    *
291    * @param charset
292    *    The charset to use for the reader.
293    *    <br>If <jk>null</jk>, <js>"UTF-8"</js> is used.
294    * @return
295    *    The HTTP response message body reader, never <jk>null</jk>.
296    *    <br>For responses without a body(e.g. HTTP 204), returns an empty reader.
297    * @throws IOException If an exception occurred.
298    */
299   public Reader asReader(Charset charset) throws IOException {
300      return new InputStreamReader(asInputStream(), charset == null ? IOUtils.UTF8 : charset);
301   }
302
303   /**
304    * Returns the HTTP response message body as a byte array.
305    *
306    *    The HTTP response message body reader, never <jk>null</jk>.
307    *    <br>For responses without a body(e.g. HTTP 204), returns an empty array.
308    *
309    * @return The HTTP response body as a byte array.
310    * @throws RestCallException If an exception occurred.
311    */
312   public byte[] asBytes() throws RestCallException {
313      if (cache == null) {
314         try {
315            cache = IOUtils.readBytes(entity.getContent());
316         } catch (IOException e) {
317            throw new RestCallException(response, e, "Could not read response body.");
318         } finally {
319            response.close();
320         }
321      }
322      return cache;
323   }
324
325
326   /**
327    * Pipes the contents of the response to the specified output stream.
328    *
329    * <ul class='notes'>
330    * <li>
331    *    The output stream is not automatically closed.
332    *    <li>
333    *       Once the input stream is exhausted, it will automatically be closed.
334    *  <li>
335    *    This method can be called multiple times if {@link #cache()} has been called.
336    *  <li>
337    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
338    *    with an inner {@link IllegalStateException} to be thrown.
339    * </ul>
340    *
341    * @param os The output stream to pipe the output to.
342    * @return The response object (for method chaining).
343    * @throws IOException If an IO exception occurred.
344    */
345   public RestResponse pipeTo(OutputStream os) throws IOException {
346      IOPipe.create(asInputStream(), os).run();
347      return response;
348   }
349
350   /**
351    * Pipes the contents of the response to the specified writer.
352    *
353    * <ul class='notes'>
354    * <li>
355    *    The writer is not automatically closed.
356    *    <li>
357    *       Once the reader is exhausted, it will automatically be closed.
358    *    <li>
359    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
360    *  <li>
361    *    This method can be called multiple times if {@link #cache()} has been called.
362    *  <li>
363    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
364    *    with an inner {@link IllegalStateException} to be thrown.
365    * </ul>
366    *
367    * @param w The writer to pipe the output to.
368    * @return The response object (for method chaining).
369    * @throws IOException If an IO exception occurred.
370    */
371   public RestResponse pipeTo(Writer w) throws IOException {
372      return pipeTo(w, false);
373   }
374
375   /**
376    * Pipes the contents of the response to the specified writer.
377    *
378    * <ul class='notes'>
379    * <li>
380    *    The writer is not automatically closed.
381    *    <li>
382    *       Once the reader is exhausted, it will automatically be closed.
383    *  <li>
384    *    This method can be called multiple times if {@link #cache()} has been called.
385    *  <li>
386    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
387    *    with an inner {@link IllegalStateException} to be thrown.
388    * </ul>
389    *
390    * @param w The writer to pipe the output to.
391    * @param charset
392    *    The charset to use for the reader.
393    *    <br>If <jk>null</jk>, <js>"UTF-8"</js> is used.
394    * @return The response object (for method chaining).
395    * @throws IOException If an IO exception occurred.
396    */
397   public RestResponse pipeTo(Writer w, Charset charset) throws IOException {
398      return pipeTo(w, charset, false);
399   }
400
401   /**
402    * Pipes the contents of the response to the specified writer.
403    *
404    * <ul class='notes'>
405    * <li>
406    *    The writer is not automatically closed.
407    *    <li>
408    *       Once the reader is exhausted, it will automatically be closed.
409    *    <li>
410    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
411    *  <li>
412    *    This method can be called multiple times if {@link #cache()} has been called.
413    *  <li>
414    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
415    *    with an inner {@link IllegalStateException} to be thrown.
416    * </ul>
417    *
418    * @param w The writer to write the output to.
419    * @param byLines Flush the writers after every line of output.
420    * @return The response object (for method chaining).
421    * @throws IOException If an IO exception occurred.
422    */
423   public RestResponse pipeTo(Writer w, boolean byLines) throws IOException {
424      return pipeTo(w, null, byLines);
425   }
426
427   /**
428    * Pipes the contents of the response to the specified writer.
429    *
430    * <ul class='notes'>
431    * <li>
432    *    The writer is not automatically closed.
433    *    <li>
434    *       Once the reader is exhausted, it will automatically be closed.
435    *  <li>
436    *    This method can be called multiple times if {@link #cache()} has been called.
437    *  <li>
438    *    Calling this method multiple times without caching enabled will cause a {@link RestCallException}
439    *    with an inner {@link IllegalStateException} to be thrown.
440    * </ul>
441    *
442    * @param w The writer to pipe the output to.
443    * @param byLines Flush the writers after every line of output.
444    * @param charset
445    *    The charset to use for the reader.
446    *    <br>If <jk>null</jk>, <js>"UTF-8"</js> is used.
447    * @return The response object (for method chaining).
448    * @throws IOException If an IO exception occurred.
449    */
450   public RestResponse pipeTo(Writer w, Charset charset, boolean byLines) throws IOException {
451      IOPipe.create(asReader(charset), w).byLines(byLines).run();
452      return response;
453   }
454
455   //------------------------------------------------------------------------------------------------------------------
456   // Retrievers
457   //------------------------------------------------------------------------------------------------------------------
458
459   /**
460    * Parses HTTP body into the specified object type.
461    *
462    * <p>
463    * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
464    *
465    * <h5 class='section'>Examples:</h5>
466    * <p class='bcode w800'>
467    *    <jc>// Parse into a linked-list of strings.</jc>
468    *    List&lt;String&gt; <jv>l1</jv> = <jv>client</jv>
469    *       .get(<jsf>URI</jsf>)
470    *       .run()
471    *       .getBody().as(LinkedList.<jk>class</jk>, String.<jk>class</jk>);
472    *
473    *    <jc>// Parse into a linked-list of beans.</jc>
474    *    List&lt;MyBean&gt; <jv>l2</jv> = <jv>client</jv>
475    *       .get(<jsf>URI</jsf>)
476    *       .run()
477    *       .getBody().as(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
478    *
479    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
480    *    List&lt;List&lt;String&gt;&gt; <jv>l3</jv> = <jv>client</jv>
481    *       .get(<jsf>URI</jsf>)
482    *       .run()
483    *       .getBody().as(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
484    *
485    *    <jc>// Parse into a map of string keys/values.</jc>
486    *    Map&lt;String,String&gt; <jv>m1</jv> = <jv>client</jv>
487    *       .get(<jsf>URI</jsf>)
488    *       .run()
489    *       .getBody().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
490    *
491    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
492    *    Map&lt;String,List&lt;MyBean&gt;&gt; <jv>m2</jv> = <jv>client</jv>
493    *       .get(<jsf>URI</jsf>)
494    *       .run()
495    *       .getBody().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
496    * </p>
497    *
498    * <p>
499    * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
500    *
501    * <p>
502    * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
503    *
504    * <p>
505    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
506    *
507    * <ul class='notes'>
508    *    <li>
509    *       Use the {@link #as(Class)} method instead if you don't need a parameterized map/collection.
510    *    <li>
511    *       You can also specify any of the following types:
512    *       <ul class='compact'>
513    *          <li>{@link RestResponseBody}/{@link HttpEntity} - Returns access to this object.
514    *          <li>{@link Reader} - Returns access to the raw reader of the response.
515    *          <li>{@link InputStream} - Returns access to the raw input stream of the response.
516    *          <li>{@link BasicHttpResource} - Raw contents will be serialized to remote resource.  Additional headers and media type will be set on request.
517    *       </ul>
518    *    <li>
519    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
520    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
521    *    with an inner {@link IllegalStateException} will be thrown.
522    *    <li>
523    *       The input stream is automatically closed after this call.
524    * </ul>
525    *
526    * @param <T> The class type of the object to create.
527    * @param type
528    *    The object type to create.
529    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
530    * @param args
531    *    The type arguments of the class if it's a collection or map.
532    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
533    *    <br>Ignored if the main type is not a map or collection.
534    * @return The parsed object.
535    * @throws RestCallException
536    *    <ul>
537    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
538    *       <li>If a connection error occurred.
539    *    </ul>
540    * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
541    */
542   public <T> T as(Type type, Type...args) throws RestCallException {
543      return as(getClassMeta(type, args));
544   }
545
546   /**
547    * Same as {@link #as(Type,Type...)} but sets the value in a mutable for fluent calls.
548    *
549    * <h5 class='section'>Example:</h5>
550    * <p class='bcode w800'>
551    *    <jc>// Parse into a linked-list of strings and also pipe to an output stream.</jc>
552    *    Mutable&lt;List&lt;String&gt;&gt; <jv>mutable</jv> = Mutable.<jsm>create()</jsm>;
553    *
554    *    <jv>client</jv>
555    *       .get(<jsf>URI</jsf>)
556    *       .run()
557    *       .cache()
558    *       .getBody().as(<jv>mutable</jv>, LinkedList.<jk>class</jk>, String.<jk>class</jk>)
559    *       .getBody().pipeTo(outputStream)
560    *       .assertStatus().is(200);
561    *
562    *    List&lt;String&gt; <jv>list</jv> = <jv>mutable</jv>.get();
563    * </p>
564    *
565    * <ul class='notes'>
566    *    <li>
567    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
568    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
569    *    with an inner {@link IllegalStateException} will be thrown.
570    *    <li>
571    *       The input stream is automatically closed after this call.
572    * </ul>
573    *
574    * @param <T> The class type of the object to create.
575    * @param m The mutable to set the parsed value in.
576    * @param type
577    *    The object type to create.
578    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
579    * @param args
580    *    The type arguments of the class if it's a collection or map.
581    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
582    *    <br>Ignored if the main type is not a map or collection.
583    * @return The response object (for method chaining).
584    * @throws RestCallException
585    *    <ul>
586    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
587    *       <li>If a connection error occurred.
588    *    </ul>
589    * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
590    */
591   public <T> RestResponse as(Mutable<T> m, Type type, Type...args) throws RestCallException {
592      m.set(as(type, args));
593      return response;
594   }
595
596   /**
597    * Same as {@link #as(Type,Type...)} except optimized for a non-parameterized class.
598    *
599    * <p>
600    * This is the preferred parse method for simple types since you don't need to cast the results.
601    *
602    * <h5 class='section'>Examples:</h5>
603    * <p class='bcode w800'>
604    *    <jc>// Parse into a string.</jc>
605    *    String <jv>string</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(String.<jk>class</jk>);
606    *
607    *    <jc>// Parse into a bean.</jc>
608    *    MyBean <jv>bean</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(MyBean.<jk>class</jk>);
609    *
610    *    <jc>// Parse into a bean array.</jc>
611    *    MyBean[] <jv>beanArray</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(MyBean[].<jk>class</jk>);
612    *
613    *    <jc>// Parse into a linked-list of objects.</jc>
614    *    List <jv>list</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(LinkedList.<jk>class</jk>);
615    *
616    *    <jc>// Parse into a map of object keys/values.</jc>
617    *    Map <jv>map</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(TreeMap.<jk>class</jk>);
618    * </p>
619    *
620    * <ul class='notes'>
621    *    <li>
622    *       You can also specify any of the following types:
623    *       <ul class='compact'>
624    *          <li>{@link RestResponseBody}/{@link HttpEntity} - Returns access to this object.
625    *          <li>{@link Reader} - Returns access to the raw reader of the response.
626    *          <li>{@link InputStream} - Returns access to the raw input stream of the response.
627    *          <li>{@link BasicHttpResource} - Raw contents will be serialized to remote resource.  Additional headers and media type will be set on request.
628    *       </ul>
629    *    <li>
630    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
631    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
632    *    with an inner {@link IllegalStateException} will be thrown.
633    *    <li>
634    *       The input stream is automatically closed after this call.
635    * </ul>
636    *
637    * @param <T>
638    *    The class type of the object being created.
639    *    See {@link #as(Type,Type...)} for details.
640    * @param type The object type to create.
641    * @return The parsed object.
642    * @throws RestCallException
643    *    If the input contains a syntax error or is malformed, or is not valid for the specified type, or if a connection
644    *    error occurred.
645    */
646   public <T> T as(Class<T> type) throws RestCallException {
647      return as(getClassMeta(type));
648   }
649
650   /**
651    * Same as {@link #as(Class)} but sets the value in a mutable for fluent calls.
652    *
653    * <h5 class='section'>Example:</h5>
654    * <p class='bcode w800'>
655    *    <jc>// Parse into a bean and also pipe to an output stream.</jc>
656    *    Mutable&lt;MyBean&gt; <jv>mutable</jv> = Mutable.<jsm>create()</jsm>;
657    *
658    *    <jv>client</jv>
659    *       .get(<jsf>URI</jsf>)
660    *       .run()
661    *       .cache()
662    *       .getBody().as(<jv>mutable</jv>, MyBean.<jk>class</jk>)
663    *       .getBody().pipeTo(<jv>outputStream</jv>)
664    *       .assertStatus().is(200);
665    *
666    *    MyBean <jv>bean</jv> = <jv>mutable</jv>.get();
667    * </p>
668    *
669    * <ul class='notes'>
670    *    <li>
671    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
672    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
673    *    with an inner {@link IllegalStateException} will be thrown.
674    *    <li>
675    *       The input stream is automatically closed after this call.
676    * </ul>
677    *
678    * @param <T> The class type of the object to create.
679    * @param m The mutable to set the parsed value in.
680    * @param type
681    *    The object type to create.
682    * @return The response object (for method chaining).
683    * @throws RestCallException
684    *    <ul>
685    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
686    *       <li>If a connection error occurred.
687    *    </ul>
688    * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
689    */
690   public <T> RestResponse as(Mutable<T> m, Class<T> type) throws RestCallException {
691      m.set(as(type));
692      return response;
693   }
694
695   /**
696    * Same as {@link #as(Class)} except allows you to predefine complex data types using the {@link ClassMeta} API.
697    *
698    * <h5 class='section'>Examples:</h5>
699    * <p class='bcode w800'>
700    *    BeanContext <jv>bc</jv> = BeanContext.<jsf>DEFAULT</jsf>;
701    *
702    *    <jc>// Parse into a linked-list of strings.</jc>
703    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm1</jv> = <jv>bc</jv>.getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);
704    *    List&lt;String> <jv>l1</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm1</jv>);
705    *
706    *    <jc>// Parse into a linked-list of beans.</jc>
707    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm2</jv> = <jv>bc</jv>.getClassMeta(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
708    *    List&lt;MyBean&gt; <jv>l2</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm2</jv>);
709    *
710    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
711    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm3</jv> = <jv>bc</jv>.getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
712    *    List&lt;List&lt;String&gt;&gt; <jv>l3</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm3</jv>);
713    *
714    *    <jc>// Parse into a map of string keys/values.</jc>
715    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm4</jv> = <jv>bc</jv>.getClassMeta(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
716    *    Map&lt;String,String&gt; <jv>m4</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm4</jv>);
717    *
718    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
719    * ClassMeta&lt;List&lt;String&gt;&gt; <jv>cm5</jv> = <jv>bc</jv>.getClassMeta(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
720    *    Map&lt;String,List&lt;MyBean&gt;&gt; <jv>m5</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm5</jv>);
721    * </p>
722    *
723    * <ul class='notes'>
724    *    <li>
725    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
726    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
727    *    with an inner {@link IllegalStateException} will be thrown.
728    *    <li>
729    *       The input stream is automatically closed after this call.
730    * </ul>
731    *
732    * @param <T> The class type of the object to create.
733    * @param type The object type to create.
734    * @return The parsed object.
735    * @throws RestCallException
736    *    <ul>
737    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
738    *       <li>If a connection error occurred.
739    *    </ul>
740    * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
741    */
742   @SuppressWarnings("unchecked")
743   public <T> T as(ClassMeta<T> type) throws RestCallException {
744      try {
745         Class<?> ic = type.getInnerClass();
746
747         if (ic.equals(RestResponseBody.class) || ic.equals(HttpEntity.class))
748            return (T)this;
749
750         if (ic.equals(Reader.class))
751            return (T)asReader();
752
753         if (ic.equals(InputStream.class))
754            return (T)asInputStream();
755
756         if (type.isType(HttpResponse.class))
757            return (T)response;
758
759         if (type.isType(HttpResource.class)) {
760            BasicHttpResource r = BasicHttpResource.of(asInputStream());
761            for (Header h : response.getAllHeaders()) {
762               if (h.getName().equalsIgnoreCase("Content-Type"))
763                  r.contentType(h);
764               else if (h.getName().equalsIgnoreCase("Content-Encoding"))
765                  r.contentEncoding(h);
766               else
767                  r.header(h);
768            }
769            return (T)r;
770         }
771
772         String ct = firstNonEmpty(response.getHeader("Content-Type").asStringOrElse("text/plain"));
773
774         if (parser == null)
775            parser = client.getMatchingParser(ct);
776
777         MediaType mt = MediaType.of(ct);
778
779         if (parser == null || (mt.toString().equals("text/plain") && ! parser.canHandle(ct))) {
780            if (type.hasStringMutater())
781               return type.getStringMutater().mutate(asString());
782         }
783
784         if (parser != null) {
785            try (Closeable in = parser.isReaderParser() ? asReader() : asInputStream()) {
786
787               ParserSessionArgs pArgs =
788                  ParserSessionArgs
789                     .create()
790                     .properties(new OMap().inner(request.getProperties()))
791                     .locale(response.getLocale())
792                     .mediaType(mt)
793                     .schema(schema);
794
795               T t = parser.createSession(pArgs).parse(in, type);
796
797               // Some HTTP responses have no body, so try to create these beans if they've got no-arg constructors.
798               if (t == null && ! type.isType(String.class)) {
799                  ConstructorInfo c = type.getInfo().getPublicConstructor();
800                  if (c != null) {
801                     try {
802                        return c.<T>invoke();
803                     } catch (ExecutableException e) {
804                        throw new ParseException(e);
805                     }
806                  }
807               }
808
809               return t;
810            }
811         }
812
813         if (type.hasReaderMutater())
814            return type.getReaderMutater().mutate(asReader());
815
816         if (type.hasInputStreamMutater())
817            return type.getInputStreamMutater().mutate(asInputStream());
818
819         throw new ParseException(
820            "Unsupported media-type in request header ''Content-Type'': ''{0}''",
821            response.getStringHeader("Content-Type")
822         );
823
824      } catch (ParseException | IOException e) {
825         response.close();
826         throw new RestCallException(response, e, "Could not parse response body.");
827      }
828   }
829
830   /**
831    * Identical to {@link #as(ClassMeta)} but sets the value in a mutable for fluent calls.
832    *
833    * <h5 class='section'>Example:</h5>
834    * <p class='bcode w800'>
835    *    <jc>// Parse into a bean and also pipe to an output stream.</jc>
836    *    Mutable&lt;List&lt;MyBean&gt;&gt; <jv>mutable</jv> = Mutable.<jsm>create()</jsm>;
837    *    ClassMeta&lt;List&lt;MyBean&gt;&gt; <jv>cm</jv> = BeanContext.<jsf>DEFAULT</jsf>.getClassMeta(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
838    *
839    *    <jv>client</jv>
840    *       .get(<jsf>URI</jsf>)
841    *       .run()
842    *       .cache()
843    *       .getBody().as(<jv>mutable</jv>, <jv>cm</jv>)
844    *       .getBody().pipeTo(<jv>outputStream</jv>)
845    *       .assertStatus().is(200);
846    *
847    *    MyBean <jv>bean</jv> = <jv>mutable</jv>.get();
848    * </p>
849    *
850    * <ul class='notes'>
851    *    <li>
852    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
853    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
854    *    with an inner {@link IllegalStateException} will be thrown.
855    *    <li>
856    *       The input stream is automatically closed after this call.
857    * </ul>
858    *
859    * @param <T> The class type of the object to create.
860    * @param m The mutable to set the parsed value in.
861    * @param type
862    *    The object type to create.
863    * @return The response object (for method chaining).
864    * @throws RestCallException
865    *    <ul>
866    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
867    *       <li>If a connection error occurred.
868    *    </ul>
869    * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
870    */
871   public <T> RestResponse as(Mutable<T> m, ClassMeta<T> type) throws RestCallException {
872      m.set(as(type));
873      return response;
874   }
875
876   /**
877    * Same as {@link #as(Class)} but allows you to run the call asynchronously.
878    *
879    * <ul class='notes'>
880    *    <li>
881    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
882    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
883    *    with an inner {@link IllegalStateException} will be thrown.
884    *    <li>
885    *       The input stream is automatically closed after the execution of the future.
886    * </ul>
887    *
888    * @param <T> The class type of the object being created.
889    * @param type The object type to create.
890    * @return The future object.
891    * @throws RestCallException If the executor service was not defined.
892    * @see
893    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
894    *    {@link Future Futures}.
895    */
896   public <T> Future<T> asFuture(final Class<T> type) throws RestCallException {
897      return client.getExecutorService().submit(
898         new Callable<T>() {
899            @Override /* Callable */
900            public T call() throws Exception {
901               return as(type);
902            }
903         }
904      );
905   }
906
907   /**
908    * Same as {@link #as(Mutable,Class)} but allows you to run the call asynchronously.
909    *
910    * <ul class='notes'>
911    *    <li>
912    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
913    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
914    *    with an inner {@link IllegalStateException} will be thrown.
915    *    <li>
916    *       The input stream is automatically closed after the execution of the future.
917    * </ul>
918    *
919    * @param <T> The class type of the object being created.
920    * @param m The mutable to set the parsed value in.
921    * @param type The object type to create.
922    * @return The response object (for method chaining).
923    * @throws RestCallException If the executor service was not defined.
924    * @see
925    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
926    *    {@link Future Futures}.
927    */
928   public <T> RestResponse asFuture(Mutable<Future<T>> m, Class<T> type) throws RestCallException {
929      m.set(asFuture(type));
930      return response;
931   }
932
933   /**
934    * Same as {@link #as(ClassMeta)} but allows you to run the call asynchronously.
935    *
936    * <ul class='notes'>
937    *    <li>
938    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
939    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
940    *    with an inner {@link IllegalStateException} will be thrown.
941    *    <li>
942    *       The input stream is automatically closed after the execution of the future.
943    * </ul>
944    *
945    * @param <T>
946    *    The class type of the object being created.
947    *    See {@link #as(Type, Type...)} for details.
948    * @param type The object type to create.
949    * @return The future object.
950    * @throws RestCallException If the executor service was not defined.
951    * @see
952    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
953    *    {@link Future Futures}.
954    */
955   public <T> Future<T> asFuture(final ClassMeta<T> type) throws RestCallException {
956      return client.getExecutorService().submit(
957         new Callable<T>() {
958            @Override /* Callable */
959            public T call() throws Exception {
960               return as(type);
961            }
962         }
963      );
964   }
965
966   /**
967    * Same as {@link #as(Mutable,ClassMeta)} but allows you to run the call asynchronously.
968    *
969    * <ul class='notes'>
970    *    <li>
971    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
972    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
973    *    with an inner {@link IllegalStateException} will be thrown.
974    *    <li>
975    *       The input stream is automatically closed after the execution of the future.
976    * </ul>
977    *
978    * @param <T>
979    *    The class type of the object being created.
980    *    See {@link #as(Type, Type...)} for details.
981    * @param m The mutable to set the parsed value in.
982    * @param type The object type to create.
983    * @return The response object (for method chaining).
984    * @throws RestCallException If the executor service was not defined.
985    * @see
986    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
987    *    {@link Future Futures}.
988    */
989   public <T> RestResponse asFuture(Mutable<Future<T>>m, ClassMeta<T> type) throws RestCallException {
990      m.set(asFuture(type));
991      return response;
992   }
993
994   /**
995    * Same as {@link #as(Type,Type...)} but allows you to run the call asynchronously.
996    *
997    * <ul class='notes'>
998    *    <li>
999    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
1000    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1001    *    with an inner {@link IllegalStateException} will be thrown.
1002    *    <li>
1003    *       The input stream is automatically closed after the execution of the future.
1004    * </ul>
1005    *
1006    * @param <T>
1007    *    The class type of the object being created.
1008    *    See {@link #as(Type, Type...)} for details.
1009    * @param type
1010    *    The object type to create.
1011    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
1012    * @param args
1013    *    The type arguments of the class if it's a collection or map.
1014    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
1015    *    <br>Ignored if the main type is not a map or collection.
1016    * @return The future object.
1017    * @throws RestCallException If the executor service was not defined.
1018    * @see
1019    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
1020    *    {@link Future Futures}.
1021    */
1022   public <T> Future<T> asFuture(final Type type, final Type...args) throws RestCallException {
1023      return client.getExecutorService().submit(
1024         new Callable<T>() {
1025            @Override /* Callable */
1026            public T call() throws Exception {
1027               return as(type, args);
1028            }
1029         }
1030      );
1031   }
1032
1033   /**
1034    * Same as {@link #as(Mutable,Type,Type...)} but allows you to run the call asynchronously.
1035    *
1036    * <ul class='notes'>
1037    *    <li>
1038    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
1039    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1040    *    with an inner {@link IllegalStateException} will be thrown.
1041    *    <li>
1042    *       The input stream is automatically closed after the execution of the future.
1043    * </ul>
1044    *
1045    * @param <T>
1046    *    The class type of the object being created.
1047    *    See {@link #as(Type, Type...)} for details.
1048    * @param m The mutable to set the parsed value in.
1049    * @param type
1050    *    The object type to create.
1051    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
1052    * @param args
1053    *    The type arguments of the class if it's a collection or map.
1054    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
1055    *    <br>Ignored if the main type is not a map or collection.
1056    * @return The response object (for method chaining).
1057    * @throws RestCallException If the executor service was not defined.
1058    * @see
1059    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
1060    *    {@link Future Futures}.
1061    */
1062   public <T> RestResponse asFuture(Mutable<Future<T>> m, Type type, Type...args) throws RestCallException {
1063      m.set(asFuture(type, args));
1064      return response;
1065   }
1066
1067   /**
1068    * Returns the contents of this body as a string.
1069    *
1070    * <ul class='notes'>
1071    *    <li>
1072    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1073    *  <li>
1074    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
1075    *    <li>
1076    *       The input stream is automatically closed after this call.
1077    * </ul>
1078    *
1079    * @return The response as a string.
1080    * @throws RestCallException
1081    *    <ul>
1082    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
1083    *       <li>If a connection error occurred.
1084    *    </ul>
1085    */
1086   public String asString() throws RestCallException {
1087      cache();
1088      try (Reader r = asReader()) {
1089         return read(r).toString();
1090      } catch (IOException e) {
1091         response.close();
1092         throw new RestCallException(response, e, "Could not read response body.");
1093      }
1094   }
1095
1096   /**
1097    * Same as {@link #asString()} but sets the value in a mutable for fluent calls.
1098    *
1099    * <ul class='notes'>
1100    *    <li>
1101    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1102    *  <li>
1103    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
1104    *    <li>
1105    *       The input stream is automatically closed after this call.
1106    * </ul>
1107    *
1108    * @param m The mutable to set the value in.
1109    * @return The response object (for method chaining).
1110    * @throws RestCallException
1111    *    <ul>
1112    *       <li>If a connection error occurred.
1113    *    </ul>
1114    */
1115   public RestResponse asString(Mutable<String> m) throws RestCallException {
1116      m.set(asString());
1117      return response;
1118   }
1119
1120   /**
1121    * Same as {@link #asString()} but allows you to run the call asynchronously.
1122    *
1123    * <ul class='notes'>
1124    *    <li>
1125    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1126    *  <li>
1127    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
1128    *    <li>
1129    *       The input stream is automatically closed after this call.
1130    * </ul>
1131    *
1132    * @return The future object.
1133    * @throws RestCallException If the executor service was not defined.
1134    * @see
1135    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
1136    *    {@link Future Futures}.
1137    */
1138   public Future<String> asStringFuture() throws RestCallException {
1139      return client.getExecutorService().submit(
1140         new Callable<String>() {
1141            @Override /* Callable */
1142            public String call() throws Exception {
1143               return asString();
1144            }
1145         }
1146      );
1147   }
1148
1149   /**
1150    * Same as {@link #asStringFuture()} but sets the value in a mutable for fluent calls.
1151    *
1152    * <ul class='notes'>
1153    *    <li>
1154    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1155    *  <li>
1156    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
1157    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1158    *    with an inner {@link IllegalStateException} will be thrown.
1159    *    <li>
1160    *       The input stream is automatically closed after this call.
1161    * </ul>
1162    *
1163    * @param m The mutable to set the value in.
1164    * @return The response object (for method chaining).
1165    * @throws RestCallException If the executor service was not defined.
1166    * @see
1167    *    RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating
1168    *    {@link Future Futures}.
1169    */
1170   public RestResponse asStringFuture(Mutable<Future<String>> m) throws RestCallException {
1171      m.set(asStringFuture());
1172      return response;
1173   }
1174
1175   /**
1176    * Same as {@link #asString()} but truncates the string to the specified length.
1177    *
1178    * <p>
1179    * If truncation occurs, the string will be suffixed with <js>"..."</js>.
1180    *
1181    * @param length The max length of the returned string.
1182    * @return The truncated string.
1183    * @throws RestCallException
1184    *    <ul>
1185    *       <li>If a connection error occurred.
1186    *    </ul>
1187    */
1188   public String asAbbreviatedString(int length) throws RestCallException {
1189      return StringUtils.abbreviate(asString(), length);
1190   }
1191
1192   /**
1193    * Same as {@link #asAbbreviatedString(int)} but sets the value in a mutable for fluent calls.
1194    *
1195    * <p>
1196    * If truncation occurs, the string will be suffixed with <js>"..."</js>.
1197    *
1198    * @param m The mutable to set the value in.
1199    * @param length The max length of the returned string.
1200    * @return The response object (for method chaining).
1201    * @throws RestCallException
1202    *    <ul>
1203    *       <li>If a connection error occurred.
1204    *    </ul>
1205    */
1206   public RestResponse asAbbreviatedString(Mutable<String> m, int length) throws RestCallException {
1207      m.set(asAbbreviatedString(length));
1208      return response;
1209   }
1210
1211   /**
1212    * Parses the output from the body into the specified type and then wraps that in a {@link PojoRest}.
1213    *
1214    * <p>
1215    * Useful if you want to quickly retrieve a single value from inside of a larger JSON document.
1216    *
1217    * @param innerType The class type of the POJO being wrapped.
1218    * @return The parsed output wrapped in a {@link PojoRest}.
1219    * @throws RestCallException
1220    *    <ul>
1221    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
1222    *       <li>If a connection error occurred.
1223    *    </ul>
1224    */
1225   public PojoRest asPojoRest(Class<?> innerType) throws RestCallException {
1226      return new PojoRest(as(innerType));
1227   }
1228
1229   /**
1230    * Same as {@link #asPojoRest(Class)} but sets the value in a mutable for fluent calls.
1231    *
1232    * @param m The mutable to set the value in.
1233    * @param innerType The class type of the POJO being wrapped.
1234    * @return The response object (for method chaining).
1235    * @throws RestCallException
1236    *    <ul>
1237    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
1238    *       <li>If a connection error occurred.
1239    *    </ul>
1240    */
1241   public RestResponse asPojoRest(Mutable<PojoRest> m, Class<?> innerType) throws RestCallException {
1242      m.set(asPojoRest(innerType));
1243      return response;
1244   }
1245
1246   /**
1247    * Converts the output from the connection into an {@link OMap} and then wraps that in a {@link PojoRest}.
1248    *
1249    * <p>
1250    * Useful if you want to quickly retrieve a single value from inside of a larger JSON document.
1251    *
1252    * @return The parsed output wrapped in a {@link PojoRest}.
1253    * @throws RestCallException
1254    *    <ul>
1255    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
1256    *       <li>If a connection error occurred.
1257    *    </ul>
1258    */
1259   public PojoRest asPojoRest() throws RestCallException {
1260      return asPojoRest(OMap.class);
1261   }
1262
1263   /**
1264    * Same as {@link #asPojoRest()} but sets the value in a mutable for fluent calls.
1265    *
1266    * @param m The mutable to set the value in.
1267    * @return The response object (for method chaining).
1268    * @throws RestCallException
1269    *    <ul>
1270    *       <li>If the input contains a syntax error or is malformed, or is not valid for the specified type.
1271    *       <li>If a connection error occurred.
1272    *    </ul>
1273    */
1274   public RestResponse asPojoRest(Mutable<PojoRest> m) throws RestCallException {
1275      m.set(asPojoRest());
1276      return response;
1277   }
1278
1279   /**
1280    * Converts the contents of the response body to a string and then matches the specified pattern against it.
1281    *
1282    * <h5 class='section'>Example:</h5>
1283    * <p class='bcode w800'>
1284    *    <jc>// Parse response using a regular expression.</jc>
1285    *    Matcher <jv>matcher</jv> = <jv>client</jv>
1286    *       .get(<jsf>URI</jsf>)
1287    *       .run()
1288    *       .getBody().asMatcher(Pattern.<jsm>compile</jsm>(<js>"foo=(.*)"</js>));
1289    *
1290    *    <jk>if</jk> (<jv>matcher</jv>.matches()) {
1291    *       String <jv>foo</jv> = <jv>matcher</jv>.group(1);
1292    *    }
1293    * </p>
1294    *
1295    * <ul class='notes'>
1296    *    <li>
1297    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1298    *  <li>
1299    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
1300    *    <li>
1301    *       The input stream is automatically closed after this call.
1302    * </ul>
1303    *
1304    * @param pattern The regular expression pattern to match.
1305    * @return The matcher.
1306    * @throws RestCallException If a connection error occurred.
1307    */
1308   public Matcher asMatcher(Pattern pattern) throws RestCallException {
1309      return pattern.matcher(asString());
1310   }
1311
1312   /**
1313    * Same as {@link #asMatcher(Pattern)} but sets the value in a mutable for fluent calls.
1314    *
1315    * <h5 class='section'>Example:</h5>
1316    * <p class='bcode w800'>
1317    *    <jc>// Parse response using a regular expression.</jc>
1318    *    Mutable&lt;Matcher&gt; <jv>mutable</jv> = Mutable.<jsm>create</jsm>();
1319    *
1320    *    <jv>client</jv>
1321    *       .get(<jsf>URI</jsf>)
1322    *       .run()
1323    *       .getBody().asMatcher(<jv>mutable</jv>, Pattern.<jsm>compile</jsm>(<js>"foo=(.*)"</js>))
1324    *       .assertStatus().is(200);
1325    *
1326    *    <jk>if</jk> (<jv>matcher</jv>.get().matches()) {
1327    *       String <jv>foo</jv> = <jv>matcher</jv>.get().group(1);
1328    *    }
1329    * </p>
1330    *
1331    *
1332    * <ul class='notes'>
1333    *    <li>
1334    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1335    *  <li>
1336    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
1337    *    <li>
1338    *       The input stream is automatically closed after this call.
1339    * </ul>
1340    *
1341    * @param m The mutable to set the value in.
1342    * @param pattern The regular expression pattern to match.
1343    * @return The response object (for method chaining).
1344    * @throws RestCallException If a connection error occurred.
1345    */
1346   public RestResponse asMatcher(Mutable<Matcher> m, Pattern pattern) throws RestCallException {
1347      m.set(pattern.matcher(asString()));
1348      return response;
1349   }
1350
1351   /**
1352    * Converts the contents of the response body to a string and then matches the specified pattern against it.
1353    *
1354    * <h5 class='section'>Example:</h5>
1355    * <p class='bcode w800'>
1356    *    <jc>// Parse response using a regular expression.</jc>
1357    *    Matcher <jv>matcher</jv> = <jv>client</jv>
1358    *       .get(<jsf>URI</jsf>)
1359    *       .run()
1360    *       .getBody().asMatcher(<js>"foo=(.*)"</js>);
1361    *
1362    *    <jk>if</jk> (<jv>matcher</jv>.matches()) {
1363    *       String <jv>foo</jv> = <jv>matcher</jv>.group(1);
1364    *    }
1365    * </p>
1366    *
1367    *
1368    * <ul class='notes'>
1369    *    <li>
1370    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1371    *  <li>
1372    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
1373    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1374    *    with an inner {@link IllegalStateException} will be thrown.
1375    *    <li>
1376    *       The input stream is automatically closed after this call.
1377    * </ul>
1378    *
1379    * @param regex The regular expression pattern to match.
1380    * @return The matcher.
1381    * @throws RestCallException If a connection error occurred.
1382    */
1383   public Matcher asMatcher(String regex) throws RestCallException {
1384      return asMatcher(regex, 0);
1385   }
1386
1387   /**
1388    * Same as {@link #asMatcher(String)} but sets the value in a mutable for fluent calls.
1389    *
1390    * <h5 class='section'>Example:</h5>
1391    * <p class='bcode w800'>
1392    *    <jc>// Parse response using a regular expression.</jc>
1393    *    Mutable&lt;Matcher&gt; <jv>mutable</jv> = Mutable.<jsm>create</jsm>();
1394    *
1395    *    <jv>client</jv>
1396    *       .get(<jsf>URI</jsf>)
1397    *       .run()
1398    *       .getBody().asMatcher(<jv>mutable</jv>, <js>"foo=(.*)"</js>)
1399    *       .assertStatus().is(200);
1400    *
1401    *    <jk>if</jk> (<jv>mutable</jv>.get().matches()) {
1402    *       String <jv>foo</jv> = <jv>mutable</jv>.get().group(1);
1403    *    }
1404    *
1405    *
1406    * <ul class='notes'>
1407    *    <li>
1408    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1409    *  <li>
1410    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
1411    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1412    *    with an inner {@link IllegalStateException} will be thrown.
1413    *    <li>
1414    *       The input stream is automatically closed after this call.
1415    * </ul>
1416    *
1417    * @param m The mutable to set the value in.
1418    * @param regex The regular expression pattern to match.
1419    * @return The response object (for method chaining).
1420    * @throws RestCallException If a connection error occurred.
1421    */
1422   public RestResponse asMatcher(Mutable<Matcher> m, String regex) throws RestCallException {
1423      asMatcher(m, regex, 0);
1424      return response;
1425   }
1426
1427   /**
1428    * Converts the contents of the response body to a string and then matches the specified pattern against it.
1429    *
1430    * <h5 class='section'>Example:</h5>
1431    * <p class='bcode w800'>
1432    *    <jc>// Parse response using a regular expression.</jc>
1433    *    Matcher <jv>matcher</jv> = <jv>client</jv>
1434    *       .get(<jsf>URI</jsf>)
1435    *       .run()
1436    *       .getBody().asMatcher(<js>"foo=(.*)"</js>, <jsf>MULTILINE</jsf> &amp; <jsf>CASE_INSENSITIVE</jsf>);
1437    *
1438    *    <jk>if</jk> (<jv>matcher</jv>.matches()) {
1439    *       String <jv>foo</jv> = <jv>matcher</jv>.group(1);
1440    *    }
1441    * </p>
1442    *
1443    *
1444    * <ul class='notes'>
1445    *    <li>
1446    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1447    *  <li>
1448    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
1449    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1450    *    with an inner {@link IllegalStateException} will be thrown.
1451    *    <li>
1452    *       The input stream is automatically closed after this call.
1453    * </ul>
1454    *
1455    * @param regex The regular expression pattern to match.
1456    * @param flags Pattern match flags.  See {@link Pattern#compile(String, int)}.
1457    * @return The matcher.
1458    * @throws RestCallException If a connection error occurred.
1459    */
1460   public Matcher asMatcher(String regex, int flags) throws RestCallException {
1461      return asMatcher(Pattern.compile(regex, flags));
1462   }
1463
1464   /**
1465    * Same as {@link #asMatcher(String,int)} but sets the value in a mutable for fluent calls.
1466    *
1467    * <h5 class='section'>Example:</h5>
1468    * <p class='bcode w800'>
1469    *    <jc>// Parse response using a regular expression.</jc>
1470    *    Mutable&lt;Matcher&gt; <jv>mutable</jv> = Mutable.<jsm>create</jsm>();
1471    *
1472    *    <jv>client</jv>
1473    *       .get(<jsf>URI</jsf>)
1474    *       .run()
1475    *       .getBody().asMatcher(<jv>mutable</jv>, <js>"foo=(.*)"</js>, <jsf>MULTILINE</jsf> &amp; <jsf>CASE_INSENSITIVE</jsf>)
1476    *       .assertStatus().is(200);
1477    *
1478    *    <jk>if</jk> (<jv>mutable</jv>.get().matches()) {
1479    *       String <jv>foo</jv> = <jv>mutable</jv>.get().group(1);
1480    *    }
1481    * </p>
1482    *
1483    *
1484    * <ul class='notes'>
1485    *    <li>
1486    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1487    *  <li>
1488    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
1489    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1490    *    with an inner {@link IllegalStateException} will be thrown.
1491    *    <li>
1492    *       The input stream is automatically closed after this call.
1493    * </ul>
1494    *
1495    * @param m The mutable to set the value in.
1496    * @param regex The regular expression pattern to match.
1497    * @param flags Pattern match flags.  See {@link Pattern#compile(String, int)}.
1498    * @return The response object (for method chaining).
1499    * @throws RestCallException If a connection error occurred.
1500    */
1501   public RestResponse asMatcher(Mutable<Matcher> m, String regex, int flags) throws RestCallException {
1502      asMatcher(m, Pattern.compile(regex, flags));
1503      return response;
1504   }
1505
1506   /**
1507    * Returns the response that created this object.
1508    *
1509    * @return The response that created this object.
1510    */
1511   public RestResponse toResponse() {
1512      return response;
1513   }
1514
1515   //------------------------------------------------------------------------------------------------------------------
1516   // Assertions
1517   //------------------------------------------------------------------------------------------------------------------
1518
1519   /**
1520    * Provides the ability to perform fluent-style assertions on this response body.
1521    *
1522    * <p>
1523    * This method is called directly from the {@link RestResponse#assertBody()} method to instantiate a fluent assertions object.
1524    *
1525    * <h5 class='section'>Examples:</h5>
1526    * <p class='bcode w800'>
1527    *    <jc>// Validates the response body equals the text "OK".</jc>
1528    *    <jv>client</jv>
1529    *       .get(<jsf>URI</jsf>)
1530    *       .run()
1531    *       .assertBody().equals(<js>"OK"</js>);
1532    *
1533    *    <jc>// Validates the response body contains the text "OK".</jc>
1534    *    <jv>client</jv>
1535    *       .get(<jsf>URI</jsf>)
1536    *       .run()
1537    *       .assertBody().contains(<js>"OK"</js>);
1538    *
1539    *    <jc>// Validates the response body passes a predicate test.</jc>
1540    *    <jv>client</jv>
1541    *       .get(<jsf>URI</jsf>)
1542    *       .run()
1543    *       .assertBody().passes(<jv>x</jv> -&gt; <jv>x</jv>.contains(<js>"OK"</js>));
1544    *
1545    *    <jc>// Validates the response body matches a regular expression.</jc>
1546    *    <jv>client</jv>
1547    *       .get(<jsf>URI</jsf>)
1548    *       .run()
1549    *       .assertBody().matches(<js>".*OK.*"</js>);
1550    *
1551    *    <jc>// Validates the response body matches a regular expression using regex flags.</jc>
1552    *    <jv>client</jv>
1553    *       .get(<jsf>URI</jsf>)
1554    *       .run()
1555    *       .assertBody().matches(<js>".*OK.*"</js>,  <jsf>MULTILINE</jsf> &amp; <jsf>CASE_INSENSITIVE</jsf>);
1556    *
1557    *    <jc>// Validates the response body matches a regular expression in the form of an existing Pattern.</jc>
1558    *    Pattern <jv>p</jv> = Pattern.<jsm>compile</jsm>(<js>".*OK.*"</js>);
1559    *    <jv>client</jv>
1560    *       .get(<jsf>URI</jsf>)
1561    *       .run()
1562    *       .assertBody().matches(<jv>p</jv>);
1563    * </p>
1564    *
1565    * <p>
1566    * The assertion test returns the original response object allowing you to chain multiple requests like so:
1567    * <p class='bcode w800'>
1568    *    <jc>// Validates the response body matches a regular expression.</jc>
1569    *    MyBean <jv>bean</jv> = <jv>client</jv>
1570    *       .get(<jsf>URI</jsf>)
1571    *       .run()
1572    *       .assertBody().matches(<js>".*OK.*"</js>);
1573    *       .assertBody().doesNotMatch(<js>".*ERROR.*"</js>)
1574    *       .getBody().as(MyBean.<jk>class</jk>);
1575    * </p>
1576    *
1577    * <ul class='notes'>
1578    *    <li>
1579    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1580    *  <li>
1581    *    This method automatically calls {@link #cache()} so that the body can be retrieved multiple times.
1582    *    <li>
1583    *       The input stream is automatically closed after this call.
1584    * </ul>
1585    *
1586    * @return A new fluent assertion object.
1587    * @throws RestCallException If REST call failed.
1588    */
1589   public FluentStringAssertion<RestResponse> assertString() throws RestCallException {
1590      return new FluentStringAssertion<>(asString(), response);
1591   }
1592
1593   /**
1594    * Provides the ability to perform fluent-style assertions on the bytes of the response body.
1595    *
1596    * <p>
1597    * This method is called directly from the {@link RestResponse#assertBodyBytes()} method to instantiate a fluent assertions object.
1598    *
1599    * <h5 class='section'>Examples:</h5>
1600    * <p class='bcode w800'>
1601    *    <jc>// Validates the response body equals the text "foo".</jc>
1602    *    <jv>client</jv>
1603    *       .get(<jsf>URI</jsf>)
1604    *       .run()
1605    *       .assertBodyBytes().hex().is(<js>"666F6F"</js>);
1606    * </p>
1607    *
1608    * <ul class='notes'>
1609    *    <li>
1610    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1611    *  <li>
1612    *    When using this method, the body is automatically cached by calling the {@link RestResponseBody#cache()}.
1613    *    <li>
1614    *       The input stream is automatically closed after this call.
1615    * </ul>
1616    *
1617    * @return A new fluent assertion object.
1618    * @throws RestCallException If REST call failed.
1619    */
1620   public FluentByteArrayAssertion<RestResponse> assertBytes() throws RestCallException {
1621      return new FluentByteArrayAssertion<>(asBytes(), response);
1622   }
1623
1624   /**
1625    * Provides the ability to perform fluent-style assertions on this response body.
1626    *
1627    * <p>
1628    * This method is called directly from the {@link RestResponse#assertBody(Class)} method to instantiate a fluent assertions object.
1629    *
1630    * <p>
1631    * Converts the body of the response to the specified object using {@link #as(Class)} and returns it as a fluent assertions object.
1632    *
1633    * <h5 class='section'>Examples:</h5>
1634    * <p class='bcode w800'>
1635    *    <jc>// Validates the response body bean is the expected value.</jc>
1636    *    <jv>client</jv>
1637    *       .get(<js>"/myBean"</js>)
1638    *       .run()
1639    *       .assertBody(MyBean.<jk>class</jk>).json().is(<js>"{foo:'bar'}"</js>);
1640    * </p>
1641    *
1642    * <ul class='notes'>
1643    *    <li>
1644    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
1645    *  <li>
1646    *    If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
1647    *    other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
1648    *    with an inner {@link IllegalStateException} will be thrown.
1649    *    <li>
1650    *       The input stream is automatically closed after this call.
1651    * </ul>
1652    *
1653    * @param type The object type to create.
1654    * @return A new fluent assertion object.
1655    * @throws RestCallException If REST call failed.
1656    */
1657   public FluentObjectAssertion<RestResponse> assertObject(Class<?> type) throws RestCallException {
1658      return new FluentObjectAssertion<>(as(type), response);
1659   }
1660
1661   //------------------------------------------------------------------------------------------------------------------
1662   // HttpEntity passthrough methods.
1663   //------------------------------------------------------------------------------------------------------------------
1664
1665   /**
1666    * Tells if the entity is capable of producing its data more than once.
1667    *
1668    * <p>
1669    * A repeatable entity's {@link #getContent()} and {@link #writeTo(OutputStream)} methods can be called more than
1670    * once whereas a non-repeatable entity's can not.
1671    *
1672    * <ul class='notes'>
1673    * <li>This method always returns <jk>true</jk> if the response body is cached (see {@link #cache()}).
1674    * </ul>
1675    *
1676    * @return <jk>true</jk> if the entity is repeatable, <jk>false</jk> otherwise.
1677    */
1678   @Override /* HttpEntity */
1679   public boolean isRepeatable() {
1680      return cached || entity.isRepeatable();
1681   }
1682
1683   /**
1684    * Tells about chunked encoding for this entity.
1685    *
1686    * <p>
1687    * The primary purpose of this method is to indicate whether chunked encoding should be used when the entity is sent.
1688    * <br>For entities that are received, it can also indicate whether the entity was received with chunked encoding.
1689    *
1690    * <p>
1691    * The behavior of wrapping entities is implementation dependent, but should respect the primary purpose.
1692    *
1693    * @return <jk>true</jk> if chunked encoding is preferred for this entity, or <jk>false</jk> if it is not.
1694    */
1695   @Override /* HttpEntity */
1696   public boolean isChunked() {
1697      return entity.isChunked();
1698   }
1699
1700   /**
1701    * Tells the length of the content, if known.
1702    *
1703    * @return
1704    *    The number of bytes of the content, or a negative number if unknown.
1705    *    <br>If the content length is known but exceeds {@link Long#MAX_VALUE}, a negative number is returned.
1706    */
1707   @Override /* HttpEntity */
1708   public long getContentLength() {
1709      return cache != null ? cache.length : entity.getContentLength();
1710   }
1711
1712   /**
1713    * Obtains the <c>Content-Type</c> header, if known.
1714    *
1715    * <p>
1716    * This is the header that should be used when sending the entity, or the one that was received with the entity.
1717    * It can include a charset attribute.
1718    *
1719    * @return The <c>Content-Type</c> header for this entity, or <jk>null</jk> if the content type is unknown.
1720    */
1721   @Override /* HttpEntity */
1722   public RestResponseHeader getContentType() {
1723      return new RestResponseHeader(request, response, entity.getContentType());
1724   }
1725
1726   /**
1727    * Obtains the Content-Encoding header, if known.
1728    *
1729    * <p>
1730    * This is the header that should be used when sending the entity, or the one that was received with the entity.
1731    * <br>Wrapping entities that modify the content encoding should adjust this header accordingly.
1732    *
1733    * @return The <c>Content-Encoding</c> header for this entity, or <jk>null</jk> if the content encoding is unknown.
1734    */
1735   @Override /* HttpEntity */
1736   public RestResponseHeader getContentEncoding() {
1737      return new RestResponseHeader(request, response, entity.getContentEncoding());
1738   }
1739
1740   /**
1741    * Returns a content stream of the entity.
1742    *
1743    * <ul class='notes'>
1744    *    <li>This method is equivalent to {@link #asInputStream()} which is the preferred method for fluent-style coding.
1745    *    <li>This input stream will auto-close once the end of stream has been reached.
1746    *    <li>It is up to the caller to properly close this stream if not fully consumed.
1747    *    <li>This method can be called multiple times if the entity is repeatable or the cache flag is set on this object.
1748    *    <li>Calling this method multiple times on a non-repeatable or cached body will throw a {@link IllegalStateException}.
1749    *       Note that this is different from the HttpClient specs for this method.
1750    * </ul>
1751    *
1752    * @return Content stream of the entity.
1753    */
1754   @Override /* HttpEntity */
1755   public InputStream getContent() throws IOException, UnsupportedOperationException {
1756      return asInputStream();
1757   }
1758
1759   /**
1760    * Writes the entity content out to the output stream.
1761    *
1762    * <ul class='notes'>
1763    *    <li>This method is equivalent to {@link #pipeTo(OutputStream)} which is the preferred method for fluent-style coding.
1764    * </ul>
1765    *
1766    * @param outstream The output stream to write entity content to.
1767    */
1768   @Override /* HttpEntity */
1769   public void writeTo(OutputStream outstream) throws IOException {
1770      pipeTo(outstream);
1771   }
1772
1773   /**
1774    * Tells whether this entity depends on an underlying stream.
1775    *
1776    * <ul class='notes'>
1777    * <li>This method always returns <jk>false</jk> if the response body is cached (see {@link #cache()}.
1778    * </ul>
1779    *
1780    * @return <jk>true</jk> if the entity content is streamed, <jk>false</jk> otherwise.
1781    */
1782   @Override /* HttpEntity */
1783   public boolean isStreaming() {
1784      return cached ? false : entity.isStreaming();
1785   }
1786
1787   /**
1788    * This method is called to indicate that the content of this entity is no longer required.
1789    *
1790    * <p>
1791    * This method is of particular importance for entities being received from a connection.
1792    * <br>The entity needs to be consumed completely in order to re-use the connection with keep-alive.
1793    *
1794    * @throws IOException If an I/O error occurs.
1795    * @deprecated Use standard java convention to ensure resource deallocation by calling {@link InputStream#close()} on
1796    * the input stream returned by {@link #getContent()}
1797    */
1798   @Override /* HttpEntity */
1799   @Deprecated
1800   public void consumeContent() throws IOException {
1801      entity.consumeContent();
1802   }
1803
1804   //------------------------------------------------------------------------------------------------------------------
1805   // Utility methods
1806   //------------------------------------------------------------------------------------------------------------------
1807
1808   private BeanContext getBeanContext() {
1809      return parser == null ? BeanContext.DEFAULT : parser;
1810   }
1811
1812   private <T> ClassMeta<T> getClassMeta(Class<T> c) {
1813      return getBeanContext().getClassMeta(c);
1814   }
1815
1816   private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
1817      return getBeanContext().getClassMeta(type, args);
1818   }
1819}