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 org.apache.juneau.parser.*;
016
017import static org.apache.juneau.httppart.HttpPartType.*;
018
019import java.lang.reflect.*;
020import java.text.*;
021import java.util.*;
022import java.util.logging.*;
023
024import org.apache.http.*;
025import org.apache.http.message.*;
026import org.apache.http.params.*;
027import org.apache.http.util.*;
028import org.apache.juneau.*;
029import org.apache.juneau.assertions.*;
030import org.apache.juneau.http.header.*;
031import org.apache.juneau.httppart.*;
032import org.apache.juneau.httppart.bean.*;
033import org.apache.juneau.internal.*;
034import org.apache.juneau.utils.*;
035
036/**
037 * Represents a response from a remote REST resource.
038 *
039 * <p>
040 * Instances of this class are created by calling the {@link RestRequest#run()} method.
041 *
042 * <ul class='seealso'>
043 *    <li class='jc'>{@link RestClient}
044 *    <li class='link'>{@doc juneau-rest-client}
045 * </ul>
046 */
047public class RestResponse implements HttpResponse {
048
049   private final RestClient client;
050   private final RestRequest request;
051   private final HttpResponse response;
052   private final Parser parser;
053   HttpPartParserSession partParser;
054   private RestResponseBody responseBody;
055   private boolean isClosed;
056
057   /**
058    * Constructor.
059    *
060    * @param client The RestClient that created this response.
061    * @param request The REST request.
062    * @param response The HTTP response.  Can be <jk>null</jk>.
063    * @param parser The overridden parser passed into {@link RestRequest#parser(Parser)}.
064    */
065   protected RestResponse(RestClient client, RestRequest request, HttpResponse response, Parser parser) {
066      this.client = client;
067      this.request = request;
068      this.parser = parser;
069      this.response = response == null ? new BasicHttpResponse(null, 0, null) : response;
070      this.responseBody = new RestResponseBody(client, request, this, parser);
071      this.partParser = client.getPartParserSession();
072   }
073
074   /**
075    * Returns the request object that created this response object.
076    *
077    * @return The request object that created this response object.
078    */
079   public RestRequest getRequest() {
080      return request;
081   }
082
083   //------------------------------------------------------------------------------------------------------------------
084   // Setters
085   //------------------------------------------------------------------------------------------------------------------
086
087   /**
088    * Consumes the response body.
089    *
090    * <p>
091    * This is equivalent to closing the input stream.
092    *
093    * @return This object (for method chaining).
094    * @throws RestCallException If one of the {@link RestCallInterceptor RestCallInterceptors} threw an exception.
095    */
096   public RestResponse consume() throws RestCallException {
097      close();
098      return this;
099   }
100
101   //------------------------------------------------------------------------------------------------------------------
102   // Status line
103   //------------------------------------------------------------------------------------------------------------------
104
105   /**
106    * Same as {@link #getStatusLine()} but sets the value in a mutable for fluent calls.
107    *
108    * @param m The mutable to set the status line in.
109    * @return This object (for method chaining).
110    */
111   public RestResponse getStatusLine(Mutable<StatusLine> m) {
112      m.set(getStatusLine());
113      return this;
114   }
115
116   /**
117    * Returns the status code of the response.
118    *
119    * Shortcut for calling <code>getStatusLine().getStatusCode()</code>.
120    *
121    * @return The status code of the response.
122    */
123   public int getStatusCode() {
124      return getStatusLine().getStatusCode();
125   }
126
127   /**
128    * Same as {@link #getStatusCode()} but sets the value in a mutable for fluent calls.
129    *
130    * @param m The mutable to set the status code in.
131    * @return This object (for method chaining).
132    */
133   public RestResponse getStatusCode(Mutable<Integer> m) {
134      m.set(getStatusCode());
135      return this;
136   }
137
138   /**
139    * Returns the status line reason phrase of the response.
140    *
141    * Shortcut for calling <code>getStatusLine().getReasonPhrase()</code>.
142    *
143    * @return The status line reason phrase of the response.
144    */
145   public String getReasonPhrase() {
146      return getStatusLine().getReasonPhrase();
147   }
148
149   /**
150    * Same as {@link #getReasonPhrase()} but sets the value in a mutable for fluent calls.
151    *
152    * @param m The mutable to set the status line reason phrase in.
153    * @return This object (for method chaining).
154    */
155   public RestResponse getReasonPhrase(Mutable<String> m) {
156      m.set(getReasonPhrase());
157      return this;
158   }
159
160   //------------------------------------------------------------------------------------------------------------------
161   // Status line assertions
162   //------------------------------------------------------------------------------------------------------------------
163
164   /**
165    * Provides the ability to perform fluent-style assertions on the response {@link StatusLine} object.
166    *
167    * <h5 class='section'>Examples:</h5>
168    * <p class='bcode w800'>
169    *    MyBean <jv>bean</jv> = <jv>client</jv>
170    *       .get(<jsf>URI</jsf>)
171    *       .run()
172    *       .assertStatus().code().is(200)
173    *       .getBody().as(MyBean.<jk>class</jk>);
174    * </p>
175    *
176    * @return A new fluent assertion object.
177    * @throws RestCallException If REST call failed.
178    */
179   public RestResponseStatusLineAssertion assertStatus() throws RestCallException {
180      return new RestResponseStatusLineAssertion(getStatusLine(), this);
181   }
182
183   /**
184    * Provides the ability to perform fluent-style assertions on the response status code.
185    *
186    * <h5 class='section'>Examples:</h5>
187    * <p class='bcode w800'>
188    *    MyBean <jv>bean</jv> = <jv>client</jv>
189    *       .get(<jsf>URI</jsf>)
190    *       .run()
191    *       .assertCode().is(200)
192    *       .getBody().as(MyBean.<jk>class</jk>);
193    * </p>
194    *
195    * @return A new fluent assertion object.
196    * @throws RestCallException If REST call failed.
197    */
198   public FluentIntegerAssertion<RestResponse> assertCode() throws RestCallException {
199      return assertStatus().code();
200   }
201
202   //------------------------------------------------------------------------------------------------------------------
203   // Headers
204   //------------------------------------------------------------------------------------------------------------------
205
206   /**
207    * Shortcut for calling <code>getHeader(name).asString()</code>.
208    *
209    * @param name The header name.
210    * @return The header value, or <jk>null</jk> if header was not found.
211    */
212   public String getStringHeader(String name) {
213      return getHeader(name).asString();
214   }
215
216   /**
217    * Shortcut for calling <code>getHeader(name).asStringOrElse(def)</code>.
218    *
219    * @param name The header name.
220    * @param def The default value if the header was not found.
221    * @return The header value, or the default if header was not found.
222    */
223   public String getStringHeader(String name, String def) {
224      return getHeader(name).asStringOrElse(def);
225   }
226
227   /**
228    * Returns the last header with the specified name.
229    *
230    * Unlike {@link #getFirstHeader(String)} and {@link #getLastHeader(String)}, this method returns an empty
231    * {@link RestResponseHeader} object instead of returning <jk>null</jk>.  This allows it to be used more easily
232    * in fluent calls.
233    *
234    * @param name The header name.
235    * @return The header.  Never <jk>null</jk>.
236    */
237   public RestResponseHeader getHeader(String name) {
238      return new RestResponseHeader(request, this, getLastHeader(name)).parser(partParser);
239   }
240
241   /**
242    * Shortcut for retrieving the response charset from the <l>Content-Type</l> header.
243    *
244    * @return The response charset.
245    * @throws RestCallException If REST call failed.
246    */
247   public String getCharacterEncoding() throws RestCallException {
248      String s = getContentType().getParameter("charset");
249      return StringUtils.isEmpty(s) ? "utf-8" : s;
250   }
251
252   /**
253    * Shortcut for retrieving the response content type from the <l>Content-Type</l> header.
254    *
255    * <p>
256    * This is equivalent to calling <c>getHeader(<js>"Content-Type"</js>).as(ContentType.<jk>class</jk>)</c>.
257    *
258    * @return The response charset.
259    * @throws RestCallException If REST call failed.
260    */
261   public ContentType getContentType() throws RestCallException {
262      return getHeader("Content-Type").as(ContentType.class);
263   }
264
265   /**
266    * Provides the ability to perform fluent-style assertions on a response header.
267    *
268    * <h5 class='section'>Examples:</h5>
269    * <p class='bcode w800'>
270    *    <jc>// Validates the content type header is provided.</jc>
271    *    <jv>client</jv>
272    *       .get(<jsf>URI</jsf>)
273    *       .run()
274    *       .assertHeader(<js>"Content-Type"</js>).exists();
275    *
276    *    <jc>// Validates the content type is JSON.</jc>
277    *    <jv>client</jv>
278    *       .get(<jsf>URI</jsf>)
279    *       .run()
280    *       .assertHeader(<js>"Content-Type"</js>).is(<js>"application/json"</js>);
281    *
282    *    <jc>// Validates the content type is JSON using test predicate.</jc>
283    *    <jv>client</jv>
284    *       .get(<jsf>URI</jsf>)
285    *       .run()
286    *       .assertHeader(<js>"Content-Type"</js>).passes(<jv>x</jv> -&gt; <jv>x</jv>.equals(<js>"application/json"</js>));
287    *
288    *    <jc>// Validates the content type is JSON by just checking for substring.</jc>
289    *    <jv>client</jv>
290    *       .get(<jsf>URI</jsf>)
291    *       .run()
292    *       .assertHeader(<js>"Content-Type"</js>).contains(<js>"json"</js>);
293    *
294    *    <jc>// Validates the content type is JSON using regular expression.</jc>
295    *    <jv>client</jv>
296    *       .get(<jsf>URI</jsf>)
297    *       .run()
298    *       .assertHeader(<js>"Content-Type"</js>).matches(<js>".*json.*"</js>);
299    *
300    *    <jc>// Validates the content type is JSON using case-insensitive regular expression.</jc>
301    *    <jv>client</jv>
302    *       .get(<jsf>URI</jsf>)
303    *       .run()
304    *       .assertHeader(<js>"Content-Type"</js>).matches(<js>".*json.*"</js>, <jsf>CASE_INSENSITIVE</jsf>);
305    * </p>
306    *
307    * <p>
308    * The assertion test returns the original response object allowing you to chain multiple requests like so:
309    * <p class='bcode w800'>
310    *    <jc>// Validates the header and converts it to a bean.</jc>
311    *    MediaType <jv>mediaType</jv> = <jv>client</jv>
312    *       .get(<jsf>URI</jsf>)
313    *       .run()
314    *       .assertHeader(<js>"Content-Type"</js>).exists()
315    *       .assertHeader(<js>"Content-Type"</js>).matches(<js>".*json.*"</js>)
316    *       .getHeader(<js>"Content-Type"</js>).as(MediaType.<jk>class</jk>);
317    * </p>
318    *
319    * @param name The header name.
320    * @return A new fluent assertion object.
321    */
322   public FluentStringAssertion<RestResponse> assertStringHeader(String name) {
323      return getHeader(name).assertString();
324   }
325
326   /**
327    * Provides the ability to perform fluent-style assertions on an integer response header.
328    *
329    * <h5 class='section'>Examples:</h5>
330    * <p class='bcode w800'>
331    *    <jc>// Validates that the response content age is greater than 1.</jc>
332    *    <jv>client</jv>
333    *       .get(<jsf>URI</jsf>)
334    *       .run()
335    *       .assertIntegerHeader(<js>"Age"</js>).isGreaterThan(1);
336    * </p>
337    *
338    * @param name The header name.
339    * @return A new fluent assertion object.
340    */
341   public FluentIntegerAssertion<RestResponse> assertIntegerHeader(String name) {
342      return getHeader(name).assertInteger();
343   }
344
345   /**
346    * Provides the ability to perform fluent-style assertions on a long response header.
347    *
348    * <h5 class='section'>Examples:</h5>
349    * <p class='bcode w800'>
350    *    <jc>// Validates that the response body is not too large.</jc>
351    *    <jv>client</jv>
352    *       .get(<jsf>URI</jsf>)
353    *       .run()
354    *       .assertLongHeader(<js>"Length"</js>).isLessThan(100000);
355    * </p>
356    *
357    * @param name The header name.
358    * @return A new fluent assertion object.
359    */
360   public FluentLongAssertion<RestResponse> assertLongHeader(String name) {
361      return getHeader(name).assertLong();
362   }
363
364   /**
365    * Provides the ability to perform fluent-style assertions on a date response header.
366    *
367    * <h5 class='section'>Examples:</h5>
368    * <p class='bcode w800'>
369    *    <jc>// Validates that the response content is not expired.</jc>
370    *    <jv>client</jv>
371    *       .get(<jsf>URI</jsf>)
372    *       .run()
373    *       .assertDateHeader(<js>"Expires"</js>).isAfterNow();
374    * </p>
375    *
376    * @param name The header name.
377    * @return A new fluent assertion object.
378    */
379   public FluentZonedDateTimeAssertion<RestResponse> assertDateHeader(String name) {
380      return getHeader(name).assertDate();
381   }
382
383   /**
384    * Provides the ability to perform fluent-style assertions on a date response header.
385    *
386    * <h5 class='section'>Examples:</h5>
387    * <p class='bcode w800'>
388    *    <jc>// Validates that the response content is not expired.</jc>
389    *    <jv>client</jv>
390    *       .get(<jsf>URI</jsf>)
391    *       .run()
392    *       .assertCsvArrayHeader(<js>"Allow"</js>).contains(<js>"GET"</js>);
393    * </p>
394    *
395    * @param name The header name.
396    * @return A new fluent assertion object.
397    */
398   public FluentListAssertion<RestResponse> assertCsvArrayHeader(String name) {
399      return getHeader(name).assertCsvArray();
400   }
401
402   /**
403    * Provides the ability to perform fluent-style assertions on the response character encoding.
404    *
405    * <h5 class='section'>Examples:</h5>
406    * <p class='bcode w800'>
407    *    <jc>// Validates that the response content charset is UTF-8.</jc>
408    *    <jv>client</jv>
409    *       .get(<jsf>URI</jsf>)
410    *       .run()
411    *       .assertCharset().is(<js>"utf-8"</js>);
412    * </p>
413    *
414    * @return A new fluent assertion object.
415    * @throws RestCallException If REST call failed.
416    */
417   public FluentStringAssertion<RestResponse> assertCharset() throws RestCallException {
418      return new FluentStringAssertion<>(getCharacterEncoding(), this);
419   }
420
421   /**
422    * Provides the ability to perform fluent-style assertions on the response content type.
423    *
424    * <h5 class='section'>Examples:</h5>
425    * <p class='bcode w800'>
426    *    <jc>// Validates that the response content is JSON.</jc>
427    *    <jv>client</jv>
428    *       .get(<jsf>URI</jsf>)
429    *       .run()
430    *       .assertContentType().is(<js>"application/json"</js>);
431    * </p>
432    *
433    * <p>
434    * Note that this is equivalent to the following code:
435    * <p class='bcode w800'>
436    *    <jc>// Validates that the response content is JSON.</jc>
437    *    <jv>client</jv>
438    *       .get(<jsf>URI</jsf>)
439    *       .run()
440    *       .assertHeader(<js>"Content-Type"</js>).is(<js>"application/json"</js>);
441    * </p>
442    *
443    * @return A new fluent assertion object.
444    */
445   public FluentStringAssertion<RestResponse> assertContentType() {
446      return getHeader("Content-Type").assertString();
447   }
448
449   //------------------------------------------------------------------------------------------------------------------
450   // Body
451   //------------------------------------------------------------------------------------------------------------------
452
453   /**
454    * Returns the body of the response.
455    *
456    * This method can be called multiple times returning the same response body each time.
457    *
458    * @return The body of the response.
459    */
460   public RestResponseBody getBody() {
461      return responseBody;
462   }
463
464   /**
465    * Provides the ability to perform fluent-style assertions on this response body.
466    *
467    * <h5 class='section'>Examples:</h5>
468    * <p class='bcode w800'>
469    *    <jc>// Validates the response body equals the text "OK".</jc>
470    *    <jv>client</jv>
471    *       .get(<jsf>URI</jsf>)
472    *       .run()
473    *       .assertBody().equals(<js>"OK"</js>);
474    *
475    *    <jc>// Validates the response body contains the text "OK".</jc>
476    *    <jv>client</jv>
477    *       .get(<jsf>URI</jsf>)
478    *       .run()
479    *       .assertBody().contains(<js>"OK"</js>);
480    *
481    *    <jc>// Validates the response body passes a predicate test.</jc>
482    *    <jv>client</jv>
483    *       .get(<jsf>URI</jsf>)
484    *       .run()
485    *       .assertBody().passes(<jv>x</jv> -&gt; <jv>x</jv>.contains(<js>"OK"</js>));
486    *
487    *    <jc>// Validates the response body matches a regular expression.</jc>
488    *    <jv>client</jv>
489    *       .get(<jsf>URI</jsf>)
490    *       .run()
491    *       .assertBody().matches(<js>".*OK.*"</js>);
492    *
493    *    <jc>// Validates the response body matches a regular expression using regex flags.</jc>
494    *    <jv>client</jv>
495    *       .get(<jsf>URI</jsf>)
496    *       .run()
497    *       .assertBody().matches(<js>".*OK.*"</js>, <jsf>MULTILINE</jsf> &amp; <jsf>CASE_INSENSITIVE</jsf>);
498    *
499    *    <jc>// Validates the response body matches a regular expression in the form of an existing Pattern.</jc>
500    *    Pattern <jv>p</jv> = Pattern.<jsm>compile</jsm>(<js>".*OK.*"</js>);
501    *    <jv>client</jv>
502    *       .get(<jsf>URI</jsf>)
503    *       .run()
504    *       .assertBody().matches(<jv>p</jv>);
505    * </p>
506    *
507    * <p>
508    * The assertion test returns the original response object allowing you to chain multiple requests like so:
509    * <p class='bcode w800'>
510    *    <jc>// Validates the response body matches a regular expression.</jc>
511    *    MyBean <jv>bean</jv> = <jv>client</jv>
512    *       .get(<jsf>URI</jsf>)
513    *       .run()
514    *       .assertBody().matches(<js>".*OK.*"</js>);
515    *       .assertBody().doesNotMatch(<js>".*ERROR.*"</js>)
516    *       .getBody().as(MyBean.<jk>class</jk>);
517    * </p>
518    *
519    * <ul class='notes'>
520    *    <li>
521    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
522    *  <li>
523    *    When using this method, the body is automatically cached by calling the {@link RestResponseBody#cache()}.
524    *    <li>
525    *       The input stream is automatically closed after this call.
526    * </ul>
527    *
528    * @return A new fluent assertion object.
529    * @throws RestCallException If REST call failed.
530    */
531   public FluentStringAssertion<RestResponse> assertBody() throws RestCallException {
532      return responseBody.cache().assertString();
533   }
534
535   /**
536    * Provides the ability to perform fluent-style assertions on the bytes of the response body.
537    *
538    * <h5 class='section'>Examples:</h5>
539    * <p class='bcode w800'>
540    *    <jc>// Validates the response body equals the text "foo".</jc>
541    *    <jv>client</jv>
542    *       .get(<jsf>URI</jsf>)
543    *       .run()
544    *       .assertBodyBytes().hex().is(<js>"666F6F"</js>);
545    * </p>
546    *
547    * <ul class='notes'>
548    *    <li>
549    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
550    *  <li>
551    *    When using this method, the body is automatically cached by calling the {@link RestResponseBody#cache()}.
552    *    <li>
553    *       The input stream is automatically closed after this call.
554    * </ul>
555    *
556    * @return A new fluent assertion object.
557    * @throws RestCallException If REST call failed.
558    */
559   public FluentByteArrayAssertion<RestResponse> assertBodyBytes() throws RestCallException {
560      return responseBody.cache().assertBytes();
561   }
562
563   /**
564    * Provides the ability to perform fluent-style assertions on this response body.
565    *
566    * <p>
567    * <p>
568    * Combines the functionality of {@link RestResponseBody#as(Class)} with {@link #assertBody()} by converting the body to the specified
569    * bean and then serializing it to simplified JSON for easy string comparison.
570    *
571    * <h5 class='section'>Examples:</h5>
572    * <p class='bcode w800'>
573    *    <jc>// Validates the response body bean is the expected value.</jc>
574    *    <jv>client</jv>
575    *       .get(<js>"/myBean"</js>)
576    *       .run()
577    *       .assertBody(MyBean.<jk>class</jk>).json().is(<js>"{foo:'bar'}"</js>);
578    * </p>
579    *
580    * <ul class='notes'>
581    *    <li>
582    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
583    *  <li>
584    *    When using this method, the body is automatically cached by calling the {@link RestResponseBody#cache()}.
585    *    <li>
586    *       The input stream is automatically closed after this call.
587    * </ul>
588    *
589    * @param type The object type to create.
590    * @return A new fluent assertion object.
591    * @throws RestCallException If REST call failed.
592    */
593   public FluentObjectAssertion<RestResponse> assertBody(Class<?> type) throws RestCallException {
594      return responseBody.cache().assertObject(type);
595   }
596
597   /**
598    * Caches the response body so that it can be read as a stream multiple times.
599    *
600    * This is equivalent to calling the following:
601    * <p class='bcode w800'>
602    *    getBody().cache();
603    * </p>
604    *
605    * @return The body of the response.
606    */
607   public RestResponse cacheBody() {
608      responseBody.cache();
609      return this;
610   }
611
612   @SuppressWarnings("unchecked")
613   <T> T as(ResponseBeanMeta rbm) {
614      Class<T> c = (Class<T>)rbm.getClassMeta().getInnerClass();
615      final RestClient rc = this.client;
616      return (T)Proxy.newProxyInstance(
617         c.getClassLoader(),
618         new Class[] { c },
619         new InvocationHandler() {
620            @Override /* InvocationHandler */
621            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
622               ResponseBeanPropertyMeta pm = rbm.getProperty(method.getName());
623               HttpPartParserSession pp = pm.getParser(partParser);
624               HttpPartSchema schema = pm.getSchema();
625               HttpPartType pt = pm.getPartType();
626               String name = pm.getPartName();
627               ClassMeta<?> type = rc.getClassMeta(method.getGenericReturnType());
628               if (pt == RESPONSE_HEADER)
629                  return getHeader(name).parser(pp).schema(schema).as(type);
630               if (pt == RESPONSE_STATUS)
631                  return getStatusCode();
632               return getBody().schema(schema).as(type);
633            }
634      });
635   }
636
637   /**
638    * Logs a message.
639    *
640    * @param level The log level.
641    * @param t The throwable cause.
642    * @param msg The message with {@link MessageFormat}-style arguments.
643    * @param args The arguments.
644    * @return This object (for method chaining).
645    */
646   public RestResponse log(Level level, Throwable t, String msg, Object...args) {
647      client.log(level, t, msg, args);
648      return this;
649   }
650
651   /**
652    * Logs a message.
653    *
654    * @param level The log level.
655    * @param msg The message with {@link MessageFormat}-style arguments.
656    * @param args The arguments.
657    * @return This object (for method chaining).
658    */
659   public RestResponse log(Level level, String msg, Object...args) {
660      client.log(level, msg, args);
661      return this;
662   }
663
664   // -----------------------------------------------------------------------------------------------------------------
665   // HttpResponse pass-through methods.
666   // -----------------------------------------------------------------------------------------------------------------
667
668   /**
669    * Obtains the status line of this response.
670    *
671    * The status line can be set using one of the setStatusLine methods, or it can be initialized in a constructor.
672    *
673    * @return The status line, or <jk>null</jk> if not yet set.
674    */
675   @Override /* HttpResponse */
676   public StatusLine getStatusLine() {
677      return response.getStatusLine();
678   }
679
680   /**
681    * Sets the status line of this response.
682    *
683    * @param statusline The status line of this response
684    */
685   @Override /* HttpResponse */
686   public void setStatusLine(StatusLine statusline) {
687      response.setStatusLine(statusline);
688   }
689
690   /**
691    * Sets the status line of this response.
692    *
693    * <p>
694    * The reason phrase will be determined based on the current locale.
695    *
696    * @param ver The HTTP version.
697    * @param code The status code.
698    */
699   @Override /* HttpResponse */
700   public void setStatusLine(ProtocolVersion ver, int code) {
701      response.setStatusLine(ver, code);
702   }
703
704   /**
705    * Sets the status line of this response with a reason phrase.
706    *
707    * @param ver The HTTP version.
708    * @param code The status code.
709    * @param reason The reason phrase, or <jk>null</jk> to omit.
710    */
711   @Override /* HttpResponse */
712   public void setStatusLine(ProtocolVersion ver, int code, String reason) {
713      response.setStatusLine(ver, code, reason);
714   }
715
716   /**
717    * Updates the status line of this response with a new status code.
718    *
719    * @param code The HTTP status code.
720    * @throws IllegalStateException If the status line has not be set.
721    */
722   @Override /* HttpResponse */
723   public void setStatusCode(int code) {
724      response.setStatusCode(code);
725   }
726
727   /**
728    * Updates the status line of this response with a new reason phrase.
729    *
730    * @param reason The new reason phrase as a single-line string, or <jk>null</jk> to unset the reason phrase.
731    * @throws IllegalStateException If the status line has not be set.
732    */
733   @Override /* HttpResponse */
734   public void setReasonPhrase(String reason) {
735      response.setReasonPhrase(reason);
736   }
737
738   /**
739    * Obtains the message entity of this response.
740    *
741    * <p>
742    * The entity is provided by calling setEntity.
743    *
744    * <ul class='notes'>
745    *    <li>Unlike the {@link HttpResponse#getEntity()} method, this method never returns a <jk>null</jk> response.
746    *       Instead, <c>getBody().isPresent()</c> can be used to determine whether the response has a body.
747    * </ul>
748    *
749    * @return The response entity.  Never <jk>null</jk>.
750    */
751   @Override /* HttpResponse */
752   public RestResponseBody getEntity() {
753      return responseBody;
754   }
755
756   /**
757    * Associates a response entity with this response.
758    *
759    * <ul class='notes'>
760    *    <li>If an entity has already been set for this response and it depends on an input stream
761    *       ({@link HttpEntity#isStreaming()} returns <jk>true</jk>), it must be fully consumed in order to ensure
762    *       release of resources.
763    * </ul>
764    *
765    * @param entity The entity to associate with this response, or <jk>null</jk> to unset.
766    */
767   @Override /* HttpResponse */
768   public void setEntity(HttpEntity entity) {
769      response.setEntity(entity);
770      this.responseBody = new RestResponseBody(client, request, this, parser);
771   }
772
773   /**
774    * Obtains the locale of this response.
775    *
776    * The locale is used to determine the reason phrase for the status code.
777    * It can be changed using {@link #setLocale(Locale)}.
778    *
779    * @return The locale of this response, never <jk>null</jk>.
780    */
781   @Override /* HttpResponse */
782   public Locale getLocale() {
783      return response.getLocale();
784   }
785
786   /**
787    * Changes the locale of this response.
788    *
789    * @param loc The new locale.
790    */
791   @Override /* HttpResponse */
792   public void setLocale(Locale loc) {
793      response.setLocale(loc);
794   }
795
796   /**
797    * Returns the protocol version this message is compatible with.
798    *
799    * @return The protocol version this message is compatible with.
800    */
801   @Override /* HttpMessage */
802   public ProtocolVersion getProtocolVersion() {
803      return response.getProtocolVersion();
804   }
805
806   /**
807    * Checks if a certain header is present in this message.
808    *
809    * <p>
810    * Header values are ignored.
811    *
812    * @param name The header name to check for.
813    * @return <jk>true</jk> if at least one header with this name is present.
814    */
815   @Override /* HttpMessage */
816   public boolean containsHeader(String name) {
817      return response.containsHeader(name);
818   }
819
820   /**
821    * Returns all the headers with a specified name of this message.
822    *
823    * Header values are ignored.
824    * <br>Headers are ordered in the sequence they were sent over a connection.
825    *
826    * @param name The name of the headers to return.
827    * @return All the headers with a specified name of this message.
828    */
829   @Override /* HttpMessage */
830   public RestResponseHeader[] getHeaders(String name) {
831      Header[] a = response.getHeaders(name);
832      RestResponseHeader[] b = new RestResponseHeader[a.length];
833      for (int i = 0; i < a.length; i++)
834         b[i] = new RestResponseHeader(request, this, a[i]).parser(partParser);
835      return b;
836   }
837
838   /**
839    * Returns the first header with a specified name of this message.
840    *
841    * Header values are ignored.
842    * <br>If there is more than one matching header in the message the first element of {@link #getHeaders(String)} is returned.
843    *
844    * @param name The name of the header to return.
845    * @return The header, or <jk>null</jk> if there is no matching header in the message.
846    */
847   @Override /* HttpMessage */
848   public RestResponseHeader getFirstHeader(String name) {
849      Header h = response.getFirstHeader(name);
850      return h == null ? null : new RestResponseHeader(request, this, h).parser(partParser);
851   }
852
853   /**
854    * Returns the last header with a specified name of this message.
855    *
856    * Header values are ignored.
857    * <br>?If there is more than one matching header in the message the last element of {@link #getHeaders(String)} is returned.
858    *
859    * @param name The name of the header to return.
860    * @return The header, or <jk>null</jk> if there is no matching header in the message.
861    */
862   @Override /* HttpMessage */
863   public RestResponseHeader getLastHeader(String name) {
864      Header h = response.getLastHeader(name);
865      return h == null ? null : new RestResponseHeader(request, this, h).parser(partParser);
866   }
867
868   /**
869    * Returns all the headers of this message.
870    *
871    * Headers are ordered in the sequence they were sent over a connection.
872    *
873    * @return All the headers of this message.
874    */
875   @Override /* HttpMessage */
876   public RestResponseHeader[] getAllHeaders() {
877      Header[] a = response.getAllHeaders();
878      RestResponseHeader[] b = new RestResponseHeader[a.length];
879      for (int i = 0; i < a.length; i++)
880         b[i] = new RestResponseHeader(request, this, a[i]).parser(partParser);
881      return b;
882   }
883
884   /**
885    * Adds a header to this message.
886    *
887    * The header will be appended to the end of the list.
888    *
889    * @param header The header to append.
890    */
891   @Override /* HttpMessage */
892   public void addHeader(Header header) {
893      response.addHeader(header);
894   }
895
896   /**
897    * Adds a header to this message.
898    *
899    * The header will be appended to the end of the list.
900    *
901    * @param name The name of the header.
902    * @param value The value of the header.
903    */
904   @Override /* HttpMessage */
905   public void addHeader(String name, String value) {
906      response.addHeader(name, value);
907   }
908
909   /**
910    * Overwrites the first header with the same name.
911    *
912    * The new header will be appended to the end of the list, if no header with the given name can be found.
913    *
914    * @param header The header to set.
915    */
916   @Override /* HttpMessage */
917   public void setHeader(Header header) {
918      response.setHeader(header);
919   }
920
921   /**
922    * Overwrites the first header with the same name.
923    *
924    * The new header will be appended to the end of the list, if no header with the given name can be found.
925    *
926    * @param name The name of the header.
927    * @param value The value of the header.
928    */
929   @Override /* HttpMessage */
930   public void setHeader(String name, String value) {
931      response.setHeader(name, value);
932   }
933
934   /**
935    * Overwrites all the headers in the message.
936    *
937    * @param headers The array of headers to set.
938    */
939   @Override /* HttpMessage */
940   public void setHeaders(Header[] headers) {
941      response.setHeaders(headers);
942   }
943
944   /**
945    * Removes a header from this message.
946    *
947    * @param header The header to remove.
948    */
949   @Override /* HttpMessage */
950   public void removeHeader(Header header) {
951      response.removeHeader(header);
952   }
953
954   /**
955    * Removes all headers with a certain name from this message.
956    *
957    * @param name The name of the headers to remove.
958    */
959   @Override /* HttpMessage */
960   public void removeHeaders(String name) {
961      response.removeHeaders(name);
962   }
963
964   /**
965    * Returns an iterator of all the headers.
966    *
967    * @return {@link Iterator} that returns {@link Header} objects in the sequence they are sent over a connection.
968    */
969   @Override /* HttpMessage */
970   public HeaderIterator headerIterator() {
971      return response.headerIterator();
972   }
973
974   /**
975    * Returns an iterator of the headers with a given name.
976    *
977    * @param name The name of the headers over which to iterate, or <jk>null</jk> for all headers.
978    * @return {@link Iterator} that returns {@link Header} objects with the argument name in the sequence they are sent over a connection.
979    */
980   @Override /* HttpMessage */
981   public HeaderIterator headerIterator(String name) {
982      return response.headerIterator(name);
983   }
984
985   /**
986    * Returns the parameters effective for this message as set by {@link #setParams(HttpParams)}.
987    *
988    * @return The parameters effective for this message as set by {@link #setParams(HttpParams)}.
989    * @deprecated Use configuration classes provided <jk>org.apache.http.config</jk> and <jk>org.apache.http.client.config</jk>.
990    */
991   @Override /* HttpMessage */
992   @Deprecated
993   public HttpParams getParams() {
994      return response.getParams();
995   }
996
997   /**
998    * Provides parameters to be used for the processing of this message.
999    *
1000    * @param params The parameters.
1001    * @deprecated Use configuration classes provided <jk>org.apache.http.config</jk> and <jk>org.apache.http.client.config</jk>.
1002    */
1003   @Override /* HttpMessage */
1004   @Deprecated
1005   public void setParams(HttpParams params) {
1006      response.setParams(params);
1007   }
1008
1009   void close() throws RestCallException {
1010      if (isClosed)
1011         return;
1012      isClosed = true;
1013      EntityUtils.consumeQuietly(response.getEntity());
1014
1015      if (request.isDebug() || client.logRequestsPredicate.test(request, this)) {
1016         if (client.logRequests == DetailLevel.SIMPLE) {
1017            client.log(client.logRequestsLevel, "HTTP {0} {1}, {2}", request.getMethod(), request.getURI(), this.getStatusLine());
1018         } else if (request.isDebug() || client.logRequests == DetailLevel.FULL) {
1019            String output = getBody().asString();
1020            StringBuilder sb = new StringBuilder();
1021            sb.append("\n=== HTTP Call (outgoing) ======================================================");
1022            sb.append("\n=== REQUEST ===\n");
1023            sb.append(request.getMethod()).append(" ").append(request.getURI());
1024            sb.append("\n---request headers---");
1025            for (Header h : request.getAllHeaders())
1026               sb.append("\n\t").append(h);
1027            if (request.hasHttpEntity()) {
1028               sb.append("\n---request entity---");
1029               HttpEntity e = request.getHttpEntity();
1030               if (e.getContentType() != null)
1031                  sb.append("\n\t").append(e.getContentType());
1032               if (e.isRepeatable()) {
1033                  try {
1034                     sb.append("\n---request content---\n").append(EntityUtils.toString(e));
1035                  } catch (Exception ex) {
1036                     sb.append("\n---request content exception---\n").append(ex.getMessage());
1037                  }
1038               }
1039            }
1040            sb.append("\n=== RESPONSE ===\n").append(getStatusLine());
1041            sb.append("\n---response headers---");
1042            for (Header h : getAllHeaders())
1043               sb.append("\n\t").append(h);
1044            sb.append("\n---response content---\n").append(output);
1045            sb.append("\n=== END =======================================================================");
1046            client.log(client.logRequestsLevel, sb.toString());
1047         }
1048      }
1049
1050      for (RestCallInterceptor r : request.interceptors) {
1051         try {
1052            r.onClose(request, this);
1053         } catch (RuntimeException | RestCallException e) {
1054            throw e;
1055         } catch (Exception e) {
1056            throw new RestCallException(this, e, "Interceptor throw exception on close");
1057         }
1058      }
1059      client.onClose(request, this);
1060   }
1061
1062   //------------------------------------------------------------------------------------------------------------------
1063   // Other methods
1064   //------------------------------------------------------------------------------------------------------------------
1065
1066   HttpResponse asHttpResponse() {
1067      return response;
1068   }
1069}