001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.client;
014
015import org.apache.juneau.parser.*;
016import org.apache.juneau.rest.client.assertion.*;
017
018import static org.apache.juneau.httppart.HttpPartType.*;
019
020import java.lang.reflect.*;
021import java.text.*;
022import java.util.*;
023import java.util.logging.*;
024
025import org.apache.http.*;
026import org.apache.http.message.*;
027import org.apache.http.params.*;
028import org.apache.http.util.*;
029import org.apache.juneau.*;
030import org.apache.juneau.assertions.*;
031import org.apache.juneau.common.internal.*;
032import org.apache.juneau.http.header.*;
033import org.apache.juneau.httppart.*;
034import org.apache.juneau.httppart.bean.*;
035import org.apache.juneau.internal.*;
036
037/**
038 * Represents a response from a remote REST resource.
039 *
040 * <p>
041 * Instances of this class are created by calling the {@link RestRequest#run()} method.
042 *
043 * <h5 class='section'>See Also:</h5><ul>
044 *    <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-client">juneau-rest-client</a>
045 * </ul>
046 */
047@FluentSetters
048public class RestResponse implements HttpResponse {
049
050   private final RestClient client;
051   private final RestRequest request;
052   private final HttpResponse response;
053   private final Parser parser;
054   private ResponseContent responseContent;
055   private boolean isClosed;
056   private HeaderList headers;
057
058   private Map<HttpPartParser,HttpPartParserSession> partParserSessions = new IdentityHashMap<>();
059   private HttpPartParserSession partParserSession;
060
061   /**
062    * Constructor.
063    *
064    * @param client The RestClient that created this response.
065    * @param request The REST request.
066    * @param response The HTTP response.  Can be <jk>null</jk>.
067    * @param parser The overridden parser passed into {@link RestRequest#parser(Parser)}.
068    */
069   protected RestResponse(RestClient client, RestRequest request, HttpResponse response, Parser parser) {
070      this.client = client;
071      this.request = request;
072      this.parser = parser;
073      this.response = response == null ? new BasicHttpResponse(null, 0, null) : response;
074      this.responseContent = new ResponseContent(client, request, this, parser);
075      this.headers = HeaderList.of(this.response.getAllHeaders());
076   }
077
078   /**
079    * Returns the request object that created this response object.
080    *
081    * @return The request object that created this response object.
082    */
083   public RestRequest getRequest() {
084      return request;
085   }
086
087   //------------------------------------------------------------------------------------------------------------------
088   // Setters
089   //------------------------------------------------------------------------------------------------------------------
090
091   /**
092    * Consumes the response body.
093    *
094    * <p>
095    * This is equivalent to closing the input stream.
096    *
097    * @return This object.
098    * @throws RestCallException If one of the {@link RestCallInterceptor RestCallInterceptors} threw an exception.
099    */
100   @FluentSetter
101   public RestResponse consume() throws RestCallException {
102      close();
103      return this;
104   }
105
106   //------------------------------------------------------------------------------------------------------------------
107   // Status line
108   //------------------------------------------------------------------------------------------------------------------
109
110   /**
111    * Returns the status code of the response.
112    *
113    * Shortcut for calling <code>getStatusLine().getStatusCode()</code>.
114    *
115    * @return The status code of the response.
116    */
117   public int getStatusCode() {
118      return getStatusLine().getStatusCode();
119   }
120
121   /**
122    * Returns the status line reason phrase of the response.
123    *
124    * Shortcut for calling <code>getStatusLine().getReasonPhrase()</code>.
125    *
126    * @return The status line reason phrase of the response.
127    */
128   public String getReasonPhrase() {
129      return getStatusLine().getReasonPhrase();
130   }
131
132   //------------------------------------------------------------------------------------------------------------------
133   // Status line assertions
134   //------------------------------------------------------------------------------------------------------------------
135
136   /**
137    * Provides the ability to perform fluent-style assertions on the response {@link StatusLine} object.
138    *
139    * <h5 class='section'>Examples:</h5>
140    * <p class='bjava'>
141    *    MyBean <jv>bean</jv> = <jv>client</jv>
142    *       .get(<jsf>URI</jsf>)
143    *       .run()
144    *       .assertStatus().asCode().is(200)
145    *       .getContent().as(MyBean.<jk>class</jk>);
146    * </p>
147    *
148    * @return A new fluent assertion object.
149    */
150   public FluentResponseStatusLineAssertion<RestResponse> assertStatus() {
151      return new FluentResponseStatusLineAssertion<>(getStatusLine(), this);
152   }
153
154   /**
155    * Provides the ability to perform fluent-style assertions on the response status code.
156    *
157    * <h5 class='section'>Examples:</h5>
158    * <p class='bjava'>
159    *    MyBean <jv>bean</jv> = <jv>client</jv>
160    *       .get(<jsf>URI</jsf>)
161    *       .run()
162    *       .assertStatus(200)
163    *       .getContent().as(MyBean.<jk>class</jk>);
164    * </p>
165    *
166    * @param value The value to assert.
167    * @return A new fluent assertion object.
168    */
169   public RestResponse assertStatus(int value) {
170      assertStatus().asCode().is(value);
171      return this;
172   }
173
174   //------------------------------------------------------------------------------------------------------------------
175   // Headers
176   //------------------------------------------------------------------------------------------------------------------
177
178   /**
179    * Shortcut for calling <code>getHeader(name).asString()</code>.
180    *
181    * @param name The header name.
182    * @return The header value, never <jk>null</jk>
183    */
184   public Optional<String> getStringHeader(String name) {
185      return getHeader(name).asString();
186   }
187
188   /**
189    * Shortcut for retrieving the response charset from the <l>Content-Type</l> header.
190    *
191    * @return The response charset.
192    * @throws RestCallException If REST call failed.
193    */
194   public String getCharacterEncoding() throws RestCallException {
195      Optional<ContentType> ct = getContentType();
196      String s = null;
197      if (ct.isPresent())
198         s = getContentType().get().getParameter("charset");
199      return StringUtils.isEmpty(s) ? "utf-8" : s;
200   }
201
202   /**
203    * Shortcut for retrieving the response content type from the <l>Content-Type</l> header.
204    *
205    * <p>
206    * This is equivalent to calling <c>getHeader(<js>"Content-Type"</js>).as(ContentType.<jk>class</jk>)</c>.
207    *
208    * @return The response charset.
209    * @throws RestCallException If REST call failed.
210    */
211   public Optional<ContentType> getContentType() throws RestCallException {
212      return getHeader("Content-Type").as(ContentType.class);
213   }
214
215   /**
216    * Provides the ability to perform fluent-style assertions on the response character encoding.
217    *
218    * <h5 class='section'>Examples:</h5>
219    * <p class='bjava'>
220    *    <jc>// Validates that the response content charset is UTF-8.</jc>
221    *    <jv>client</jv>
222    *       .get(<jsf>URI</jsf>)
223    *       .run()
224    *       .assertCharset().is(<js>"utf-8"</js>);
225    * </p>
226    *
227    * @return A new fluent assertion object.
228    * @throws RestCallException If REST call failed.
229    */
230   public FluentStringAssertion<RestResponse> assertCharset() throws RestCallException {
231      return new FluentStringAssertion<>(getCharacterEncoding(), this);
232   }
233
234   /**
235    * Provides the ability to perform fluent-style assertions on a response header.
236    *
237    * <h5 class='section'>Examples:</h5>
238    * <p class='bjava'>
239    *    <jc>// Validates the content type header is provided.</jc>
240    *    <jv>client</jv>
241    *       .get(<jsf>URI</jsf>)
242    *       .run()
243    *       .assertHeader(<js>"Content-Type"</js>).exists();
244    *
245    *    <jc>// Validates the content type is JSON.</jc>
246    *    <jv>client</jv>
247    *       .get(<jsf>URI</jsf>)
248    *       .run()
249    *       .assertHeader(<js>"Content-Type"</js>).is(<js>"application/json"</js>);
250    *
251    *    <jc>// Validates the content type is JSON using test predicate.</jc>
252    *    <jv>client</jv>
253    *       .get(<jsf>URI</jsf>)
254    *       .run()
255    *       .assertHeader(<js>"Content-Type"</js>).is(<jv>x</jv> -&gt; <jv>x</jv>.equals(<js>"application/json"</js>));
256    *
257    *    <jc>// Validates the content type is JSON by just checking for substring.</jc>
258    *    <jv>client</jv>
259    *       .get(<jsf>URI</jsf>)
260    *       .run()
261    *       .assertHeader(<js>"Content-Type"</js>).contains(<js>"json"</js>);
262    *
263    *    <jc>// Validates the content type is JSON using regular expression.</jc>
264    *    <jv>client</jv>
265    *       .get(<jsf>URI</jsf>)
266    *       .run()
267    *       .assertHeader(<js>"Content-Type"</js>).isPattern(<js>".*json.*"</js>);
268    *
269    *    <jc>// Validates the content type is JSON using case-insensitive regular expression.</jc>
270    *    <jv>client</jv>
271    *       .get(<jsf>URI</jsf>)
272    *       .run()
273    *       .assertHeader(<js>"Content-Type"</js>).isPattern(<js>".*json.*"</js>, <jsf>CASE_INSENSITIVE</jsf>);
274    * </p>
275    *
276    * <p>
277    * The assertion test returns the original response object allowing you to chain multiple requests like so:
278    * <p class='bjava'>
279    *    <jc>// Validates the header and converts it to a bean.</jc>
280    *    MediaType <jv>mediaType</jv> = <jv>client</jv>
281    *       .get(<jsf>URI</jsf>)
282    *       .run()
283    *       .assertHeader(<js>"Content-Type"</js>).isNotEmpty()
284    *       .assertHeader(<js>"Content-Type"</js>).isPattern(<js>".*json.*"</js>)
285    *       .getHeader(<js>"Content-Type"</js>).as(MediaType.<jk>class</jk>);
286    * </p>
287    *
288    * @param name The header name.
289    * @return A new fluent assertion object.
290    */
291   public FluentResponseHeaderAssertion<RestResponse> assertHeader(String name) {
292      return new FluentResponseHeaderAssertion<>(getHeader(name), this);
293   }
294
295   //------------------------------------------------------------------------------------------------------------------
296   // Body
297   //------------------------------------------------------------------------------------------------------------------
298
299   /**
300    * Returns the body of the response.
301    *
302    * This method can be called multiple times returning the same response body each time.
303    *
304    * @return The body of the response.
305    */
306   public ResponseContent getContent() {
307      return responseContent;
308   }
309
310   /**
311    * Provides the ability to perform fluent-style assertions on this response body.
312    *
313    * <h5 class='section'>Examples:</h5>
314    * <p class='bjava'>
315    *    <jc>// Validates the response body equals the text "OK".</jc>
316    *    <jv>client</jv>
317    *       .get(<jsf>URI</jsf>)
318    *       .run()
319    *       .assertContent().is(<js>"OK"</js>);
320    *
321    *    <jc>// Validates the response body contains the text "OK".</jc>
322    *    <jv>client</jv>
323    *       .get(<jsf>URI</jsf>)
324    *       .run()
325    *       .assertContent().isContains(<js>"OK"</js>);
326    *
327    *    <jc>// Validates the response body passes a predicate test.</jc>
328    *    <jv>client</jv>
329    *       .get(<jsf>URI</jsf>)
330    *       .run()
331    *       .assertContent().is(<jv>x</jv> -&gt; <jv>x</jv>.contains(<js>"OK"</js>));
332    *
333    *    <jc>// Validates the response body matches a regular expression.</jc>
334    *    <jv>client</jv>
335    *       .get(<jsf>URI</jsf>)
336    *       .run()
337    *       .assertContent().isPattern(<js>".*OK.*"</js>);
338    *
339    *    <jc>// Validates the response body matches a regular expression using regex flags.</jc>
340    *    <jv>client</jv>
341    *       .get(<jsf>URI</jsf>)
342    *       .run()
343    *       .assertContent().isPattern(<js>".*OK.*"</js>, <jsf>MULTILINE</jsf> &amp; <jsf>CASE_INSENSITIVE</jsf>);
344    *
345    *    <jc>// Validates the response body matches a regular expression in the form of an existing Pattern.</jc>
346    *    Pattern <jv>pattern</jv> = Pattern.<jsm>compile</jsm>(<js>".*OK.*"</js>);
347    *    <jv>client</jv>
348    *       .get(<jsf>URI</jsf>)
349    *       .run()
350    *       .assertContent().isPattern(<jv>pattern</jv>);
351    * </p>
352    *
353    * <p>
354    * The assertion test returns the original response object allowing you to chain multiple requests like so:
355    * <p class='bjava'>
356    *    <jc>// Validates the response body matches a regular expression.</jc>
357    *    MyBean <jv>bean</jv> = <jv>client</jv>
358    *       .get(<jsf>URI</jsf>)
359    *       .run()
360    *       .assertContent().isPattern(<js>".*OK.*"</js>);
361    *       .assertContent().isNotPattern(<js>".*ERROR.*"</js>)
362    *       .getContent().as(MyBean.<jk>class</jk>);
363    * </p>
364    *
365    * <h5 class='section'>Notes:</h5><ul>
366    *    <li class='note'>
367    *       If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
368    *  <li class='note'>
369    *    When using this method, the body is automatically cached by calling the {@link ResponseContent#cache()}.
370    *    <li class='note'>
371    *       The input stream is automatically closed after this call.
372    * </ul>
373    *
374    * @return A new fluent assertion object.
375    */
376   public FluentResponseBodyAssertion<RestResponse> assertContent() {
377      return new FluentResponseBodyAssertion<>(responseContent, this);
378   }
379
380   /**
381    * Provides the ability to perform fluent-style assertions on this response body.
382    *
383    * <p>
384    * A shortcut for calling <c>assertContent().is(<jv>value</jv>)</c>.
385    *
386    * <h5 class='section'>Examples:</h5>
387    * <p class='bjava'>
388    *    <jc>// Validates the response body equals the text "OK".</jc>
389    *    <jv>client</jv>
390    *       .get(<jsf>URI</jsf>)
391    *       .run()
392    *       .assertContent(<js>"OK"</js>);
393    * </p>
394    *
395    * @param value The value to assert.
396    * @return This object.
397    */
398   public RestResponse assertContent(String value) {
399      assertContent().is(value);
400      return this;
401   }
402
403   /**
404    * Provides the ability to perform fluent-style assertions on this response body.
405    *
406    * <p>
407    * A shortcut for calling <c>assertContent().asString().isMatches(<jv>value</jv>)</c>.
408    *
409    * @see FluentStringAssertion#isMatches(String)
410    * @param value The value to assert.
411    * @return This object.
412    */
413   public RestResponse assertContentMatches(String value) {
414      assertContent().asString().isMatches(value);
415      return this;
416   }
417
418   /**
419    * Caches the response body so that it can be read as a stream multiple times.
420    *
421    * This is equivalent to calling the following:
422    * <p class='bjava'>
423    *    getContent().cache();
424    * </p>
425    *
426    * @return The body of the response.
427    */
428   @FluentSetter
429   public RestResponse cacheContent() {
430      responseContent.cache();
431      return this;
432   }
433
434   @SuppressWarnings("unchecked")
435   <T> T as(ResponseBeanMeta rbm) {
436      Class<T> c = (Class<T>)rbm.getClassMeta().getInnerClass();
437      final RestClient rc = this.client;
438      return (T)Proxy.newProxyInstance(
439         c.getClassLoader(),
440         new Class[] { c },
441         new InvocationHandler() {
442            @Override /* InvocationHandler */
443            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
444               ResponseBeanPropertyMeta pm = rbm.getProperty(method.getName());
445               HttpPartParserSession pp = getPartParserSession(pm.getParser().orElse(rc.getPartParser()));
446               HttpPartSchema schema = pm.getSchema();
447               HttpPartType pt = pm.getPartType();
448               String name = pm.getPartName().orElse(null);
449               ClassMeta<?> type = rc.getBeanContext().getClassMeta(method.getGenericReturnType());
450               if (pt == RESPONSE_HEADER)
451                  return getHeader(name).parser(pp).schema(schema).as(type).orElse(null);
452               if (pt == RESPONSE_STATUS)
453                  return getStatusCode();
454               return getContent().schema(schema).as(type);
455            }
456      });
457   }
458
459   /**
460    * Logs a message.
461    *
462    * @param level The log level.
463    * @param t The throwable cause.
464    * @param msg The message with {@link MessageFormat}-style arguments.
465    * @param args The arguments.
466    * @return This object.
467    */
468   public RestResponse log(Level level, Throwable t, String msg, Object...args) {
469      client.log(level, t, msg, args);
470      return this;
471   }
472
473   /**
474    * Logs a message.
475    *
476    * @param level The log level.
477    * @param msg The message with {@link MessageFormat}-style arguments.
478    * @param args The arguments.
479    * @return This object.
480    */
481   public RestResponse log(Level level, String msg, Object...args) {
482      client.log(level, msg, args);
483      return this;
484   }
485
486   // -----------------------------------------------------------------------------------------------------------------
487   // HttpResponse pass-through methods.
488   // -----------------------------------------------------------------------------------------------------------------
489
490   /**
491    * Obtains the status line of this response.
492    *
493    * The status line can be set using one of the setStatusLine methods, or it can be initialized in a constructor.
494    *
495    * @return The status line, or <jk>null</jk> if not yet set.
496    */
497   @Override /* HttpResponse */
498   public ResponseStatusLine getStatusLine() {
499      return new ResponseStatusLine(this, response.getStatusLine());
500   }
501
502   /**
503    * Sets the status line of this response.
504    *
505    * @param statusline The status line of this response
506    */
507   @Override /* HttpResponse */
508   public void setStatusLine(StatusLine statusline) {
509      response.setStatusLine(statusline);
510   }
511
512   /**
513    * Sets the status line of this response.
514    *
515    * <p>
516    * The reason phrase will be determined based on the current locale.
517    *
518    * @param ver The HTTP version.
519    * @param code The status code.
520    */
521   @Override /* HttpResponse */
522   public void setStatusLine(ProtocolVersion ver, int code) {
523      response.setStatusLine(ver, code);
524   }
525
526   /**
527    * Sets the status line of this response with a reason phrase.
528    *
529    * @param ver The HTTP version.
530    * @param code The status code.
531    * @param reason The reason phrase, or <jk>null</jk> to omit.
532    */
533   @Override /* HttpResponse */
534   public void setStatusLine(ProtocolVersion ver, int code, String reason) {
535      response.setStatusLine(ver, code, reason);
536   }
537
538   /**
539    * Updates the status line of this response with a new status code.
540    *
541    * @param code The HTTP status code.
542    * @throws IllegalStateException If the status line has not be set.
543    */
544   @Override /* HttpResponse */
545   public void setStatusCode(int code) {
546      response.setStatusCode(code);
547   }
548
549   /**
550    * Updates the status line of this response with a new reason phrase.
551    *
552    * @param reason The new reason phrase as a single-line string, or <jk>null</jk> to unset the reason phrase.
553    * @throws IllegalStateException If the status line has not be set.
554    */
555   @Override /* HttpResponse */
556   public void setReasonPhrase(String reason) {
557      response.setReasonPhrase(reason);
558   }
559
560   /**
561    * Obtains the message entity of this response.
562    *
563    * <p>
564    * The entity is provided by calling setEntity.
565    *
566    * <h5 class='section'>Notes:</h5><ul>
567    *    <li class='note'>Unlike the {@link HttpResponse#getEntity()} method, this method never returns a <jk>null</jk> response.
568    *       Instead, <c>getContent().isPresent()</c> can be used to determine whether the response has a body.
569    * </ul>
570    *
571    * @return The response entity.  Never <jk>null</jk>.
572    */
573   @Override /* HttpResponse */
574   public ResponseContent getEntity() {
575      return responseContent;
576   }
577
578   /**
579    * Associates a response entity with this response.
580    *
581    * <h5 class='section'>Notes:</h5><ul>
582    *    <li class='note'>If an entity has already been set for this response and it depends on an input stream
583    *       ({@link HttpEntity#isStreaming()} returns <jk>true</jk>), it must be fully consumed in order to ensure
584    *       release of resources.
585    * </ul>
586    *
587    * @param entity The entity to associate with this response, or <jk>null</jk> to unset.
588    */
589   @Override /* HttpResponse */
590   public void setEntity(HttpEntity entity) {
591      response.setEntity(entity);
592      this.responseContent = new ResponseContent(client, request, this, parser);
593   }
594
595   /**
596    * Obtains the locale of this response.
597    *
598    * The locale is used to determine the reason phrase for the status code.
599    * It can be changed using {@link #setLocale(Locale)}.
600    *
601    * @return The locale of this response, never <jk>null</jk>.
602    */
603   @Override /* HttpResponse */
604   public Locale getLocale() {
605      return response.getLocale();
606   }
607
608   /**
609    * Changes the locale of this response.
610    *
611    * @param loc The new locale.
612    */
613   @Override /* HttpResponse */
614   public void setLocale(Locale loc) {
615      response.setLocale(loc);
616   }
617
618   /**
619    * Returns the protocol version this message is compatible with.
620    *
621    * @return The protocol version this message is compatible with.
622    */
623   @Override /* HttpMessage */
624   public ProtocolVersion getProtocolVersion() {
625      return response.getProtocolVersion();
626   }
627
628   /**
629    * Checks if a certain header is present in this message.
630    *
631    * <p>
632    * Header values are ignored.
633    *
634    * @param name The header name to check for.
635    * @return <jk>true</jk> if at least one header with this name is present.
636    */
637   @Override /* HttpMessage */
638   public boolean containsHeader(String name) {
639      return response.containsHeader(name);
640   }
641
642   /**
643    * Returns all the headers with a specified name of this message.
644    *
645    * Header values are ignored.
646    * <br>Headers are ordered in the sequence they were sent over a connection.
647    *
648    * @param name The name of the headers to return.
649    * @return All the headers with a specified name of this message.
650    */
651   @Override /* HttpMessage */
652   public ResponseHeader[] getHeaders(String name) {
653      return headers.stream(name).map(x -> new ResponseHeader(name, request, this, x).parser(getPartParserSession())).toArray(ResponseHeader[]::new);
654   }
655
656   /**
657    * Returns the first header with a specified name of this message.
658    *
659    * <p>
660    * If there is more than one matching header in the message the first element of {@link #getHeaders(String)} is returned.
661    * <p>
662    * This method always returns a value so that you can perform assertions on the result.
663    *
664    * @param name The name of the header to return.
665    * @return The header, never <jk>null</jk>.
666    */
667   @Override /* HttpMessage */
668   public ResponseHeader getFirstHeader(String name) {
669      return new ResponseHeader(name, request, this, headers.getFirst(name).orElse(null)).parser(getPartParserSession());
670   }
671
672   /**
673    * Returns the last header with a specified name of this message.
674    *
675    * <p>
676    * If there is more than one matching header in the message the last element of {@link #getHeaders(String)} is returned.
677    * <p>
678    * This method always returns a value so that you can perform assertions on the result.
679    *
680    * @param name The name of the header to return.
681    * @return The header, never <jk>null</jk>.
682    */
683   @Override /* HttpMessage */
684   public ResponseHeader getLastHeader(String name) {
685      return new ResponseHeader(name, request, this, headers.getLast(name).orElse(null)).parser(getPartParserSession());
686   }
687
688   /**
689    * Returns the response header with the specified name.
690    *
691    * <p>
692    * If more that one header with the given name exists the values will be combined with <js>", "</js> as per <a href='https://tools.ietf.org/html/rfc2616#section-4.2'>RFC 2616 Section 4.2</a>.
693    *
694    * @param name The name of the header to return.
695    * @return The header, never <jk>null</jk>.
696    */
697   public ResponseHeader getHeader(String name) {
698      return new ResponseHeader(name, request, this, headers.get(name).orElse(null)).parser(getPartParserSession());
699   }
700
701   /**
702    * Returns all the headers of this message.
703    *
704    * Headers are ordered in the sequence they were sent over a connection.
705    *
706    * @return All the headers of this message.
707    */
708   @Override /* HttpMessage */
709   public ResponseHeader[] getAllHeaders() {
710      return headers.stream().map(x -> new ResponseHeader(x.getName(), request, this, x).parser(getPartParserSession())).toArray(ResponseHeader[]::new);
711   }
712
713   /**
714    * Adds a header to this message.
715    *
716    * The header will be appended to the end of the list.
717    *
718    * @param header The header to append.
719    */
720   @Override /* HttpMessage */
721   public void addHeader(Header header) {
722      headers.append(header);
723   }
724
725   /**
726    * Adds a header to this message.
727    *
728    * The header will be appended to the end of the list.
729    *
730    * @param name The name of the header.
731    * @param value The value of the header.
732    */
733   @Override /* HttpMessage */
734   public void addHeader(String name, String value) {
735      headers.append(name, value);
736   }
737
738   /**
739    * Overwrites the first header with the same name.
740    *
741    * The new header will be appended to the end of the list, if no header with the given name can be found.
742    *
743    * @param header The header to set.
744    */
745   @Override /* HttpMessage */
746   public void setHeader(Header header) {
747      headers.set(header);
748   }
749
750   /**
751    * Overwrites the first header with the same name.
752    *
753    * The new header will be appended to the end of the list, if no header with the given name can be found.
754    *
755    * @param name The name of the header.
756    * @param value The value of the header.
757    */
758   @Override /* HttpMessage */
759   public void setHeader(String name, String value) {
760      headers.set(name, value);
761   }
762
763   /**
764    * Overwrites all the headers in the message.
765    *
766    * @param headers The array of headers to set.
767    */
768   @Override /* HttpMessage */
769   public void setHeaders(Header[] headers) {
770      this.headers = HeaderList.of(headers);
771   }
772
773   /**
774    * Removes a header from this message.
775    *
776    * @param header The header to remove.
777    */
778   @Override /* HttpMessage */
779   public void removeHeader(Header header) {
780      headers.remove(header);
781   }
782
783   /**
784    * Removes all headers with a certain name from this message.
785    *
786    * @param name The name of the headers to remove.
787    */
788   @Override /* HttpMessage */
789   public void removeHeaders(String name) {
790      headers.remove(name);
791   }
792
793   /**
794    * Returns an iterator of all the headers.
795    *
796    * @return {@link Iterator} that returns {@link Header} objects in the sequence they are sent over a connection.
797    */
798   @Override /* HttpMessage */
799   public HeaderIterator headerIterator() {
800      return headers.headerIterator();
801   }
802
803   /**
804    * Returns an iterator of the headers with a given name.
805    *
806    * @param name The name of the headers over which to iterate, or <jk>null</jk> for all headers.
807    * @return {@link Iterator} that returns {@link Header} objects with the argument name in the sequence they are sent over a connection.
808    */
809   @Override /* HttpMessage */
810   public HeaderIterator headerIterator(String name) {
811      return headers.headerIterator(name);
812   }
813
814   /**
815    * Returns the parameters effective for this message as set by {@link #setParams(HttpParams)}.
816    *
817    * @return The parameters effective for this message as set by {@link #setParams(HttpParams)}.
818    * @deprecated Use configuration classes provided <jk>org.apache.http.config</jk> and <jk>org.apache.http.client.config</jk>.
819    */
820   @Override /* HttpMessage */
821   @Deprecated
822   public HttpParams getParams() {
823      return response.getParams();
824   }
825
826   /**
827    * Provides parameters to be used for the processing of this message.
828    *
829    * @param params The parameters.
830    * @deprecated Use configuration classes provided <jk>org.apache.http.config</jk> and <jk>org.apache.http.client.config</jk>.
831    */
832   @Override /* HttpMessage */
833   @Deprecated
834   public void setParams(HttpParams params) {
835      response.setParams(params);
836   }
837
838   void close() throws RestCallException {
839      if (isClosed)
840         return;
841      isClosed = true;
842      EntityUtils.consumeQuietly(response.getEntity());
843
844      if (!request.isLoggingSuppressed() && (request.isDebug() || client.logRequestsPredicate.test(request, this))) {
845         if (client.logRequests == DetailLevel.SIMPLE) {
846            client.log(client.logRequestsLevel, "HTTP {0} {1}, {2}", request.getMethod(), request.getURI(), this.getStatusLine());
847         } else if (request.isDebug() || client.logRequests == DetailLevel.FULL) {
848            String output = getContent().asString();
849            StringBuilder sb = new StringBuilder();
850            sb.append("\n=== HTTP Call (outgoing) ======================================================");
851            sb.append("\n=== REQUEST ===\n");
852            sb.append(request.getMethod()).append(" ").append(request.getURI());
853            sb.append("\n---request headers---");
854            request.getHeaders().forEach(x -> sb.append("\n\t").append(x));
855            if (request.hasHttpEntity()) {
856               sb.append("\n---request entity---");
857               HttpEntity e = request.getHttpEntity();
858               if (e.getContentType() != null)
859                  sb.append("\n\t").append(e.getContentType());
860               if (e.isRepeatable()) {
861                  try {
862                     sb.append("\n---request content---\n").append(EntityUtils.toString(e));
863                  } catch (Exception ex) {
864                     sb.append("\n---request content exception---\n").append(ex.getMessage());
865                  }
866               }
867            }
868            sb.append("\n=== RESPONSE ===\n").append(getStatusLine());
869            sb.append("\n---response headers---");
870            for (Header h : getAllHeaders())
871               sb.append("\n\t").append(h);
872            sb.append("\n---response content---\n").append(output);
873            sb.append("\n=== END =======================================================================");
874            client.log(client.logRequestsLevel, sb.toString());
875         }
876      }
877
878      for (RestCallInterceptor r : request.interceptors) {
879         try {
880            r.onClose(request, this);
881         } catch (RuntimeException | RestCallException e) {
882            throw e;
883         } catch (Exception e) {
884            throw new RestCallException(this, e, "Interceptor throw exception on close");
885         }
886      }
887      client.onCallClose(request, this);
888   }
889
890   //------------------------------------------------------------------------------------------------------------------
891   // Other methods
892   //------------------------------------------------------------------------------------------------------------------
893
894   /**
895    * Creates a session of the specified part parser.
896    *
897    * @param parser The parser to create a session for.
898    * @return A session of the specified parser.
899    */
900   protected HttpPartParserSession getPartParserSession(HttpPartParser parser) {
901      HttpPartParserSession s = partParserSessions.get(parser);
902      if (s == null) {
903         s = parser.getPartSession();
904         partParserSessions.put(parser, s);
905      }
906      return s;
907   }
908
909   /**
910    * Creates a session of the client-default parat parser.
911    *
912    * @return A session of the specified parser.
913    */
914   protected HttpPartParserSession getPartParserSession() {
915      if (partParserSession == null)
916         partParserSession = client.getPartParser().getPartSession();
917      return partParserSession;
918   }
919
920   HttpResponse asHttpResponse() {
921      return response;
922   }
923
924   //-----------------------------------------------------------------------------------------------------------------
925   // Fluent setters
926   //-----------------------------------------------------------------------------------------------------------------
927
928   // <FluentSetters>
929
930   // </FluentSetters>
931}