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.httppart.HttpPartType.*;
016import java.lang.reflect.*;
017import java.util.*;
018import java.util.regex.*;
019
020import org.apache.http.*;
021import org.apache.juneau.*;
022import org.apache.juneau.assertions.*;
023import org.apache.juneau.http.*;
024import org.apache.juneau.http.header.*;
025import org.apache.juneau.httppart.*;
026import org.apache.juneau.oapi.*;
027import org.apache.juneau.parser.ParseException;
028import org.apache.juneau.reflect.*;
029import org.apache.juneau.utils.*;
030
031/**
032 * Represents a single header on an HTTP response.
033 *
034 * <p>
035 * An extension of an HttpClient {@link Header} that provides various support for converting the header to POJOs and
036 * other convenience methods.
037 *
038 * <ul class='seealso'>
039 *    <li class='jc'>{@link RestClient}
040 *    <li class='link'>{@doc juneau-rest-client}
041 * </ul>
042 */
043public class RestResponseHeader implements Header {
044
045   static final Header NULL_HEADER = new Header() {
046
047      @Override /* Header */
048      public String getName() {
049         return null;
050      }
051
052      @Override /* Header */
053      public String getValue() {
054         return null;
055      }
056
057      @Override /* Header */
058      public HeaderElement[] getElements() throws org.apache.http.ParseException {
059         return new HeaderElement[0];
060      }
061   };
062
063   private final Header header;
064   private final RestRequest request;
065   private final RestResponse response;
066   private HttpPartParserSession parser;
067   private HttpPartSchema schema;
068
069   /**
070    * Constructor.
071    *
072    * @param request The request object.
073    * @param response The response object.
074    * @param header The wrapped header.  Can be <jk>null</jk>.
075    */
076   public RestResponseHeader(RestRequest request, RestResponse response, Header header) {
077      this.request = request;
078      this.response = response;
079      this.header = header == null ? NULL_HEADER : header;
080      parser(null);
081   }
082
083   //------------------------------------------------------------------------------------------------------------------
084   // Setters
085   //------------------------------------------------------------------------------------------------------------------
086
087   /**
088    * Specifies the part schema for this header.
089    *
090    * <p>
091    * Used by schema-based part parsers such as {@link OpenApiParser}.
092    *
093    * @param value
094    *    The part schema.
095    * @return This object (for method chaining).
096    */
097   public RestResponseHeader schema(HttpPartSchema value) {
098      this.schema = value;
099      return this;
100   }
101
102   /**
103    * Specifies the part parser to use for this header.
104    *
105    * <p>
106    * If not specified, uses the part parser defined on the client by calling {@link RestClientBuilder#partParser(Class)}.
107    *
108    * @param value
109    *    The new part parser to use for this header.
110    *    <br>If <jk>null</jk>, {@link SimplePartParser#DEFAULT} will be used.
111    * @return This object (for method chaining).
112    */
113   public RestResponseHeader parser(HttpPartParserSession value) {
114      this.parser = value == null ? SimplePartParser.DEFAULT_SESSION : value;
115      return this;
116   }
117
118   //------------------------------------------------------------------------------------------------------------------
119   // Retrievers
120   //------------------------------------------------------------------------------------------------------------------
121
122   /**
123    * Returns <jk>true</jk> if this header exists on the response.
124    *
125    * @return <jk>true</jk> if this header exists on the response.
126    */
127   public boolean exists() {
128      return header != NULL_HEADER;
129   }
130
131   /**
132    * Returns the value of this header as a string.
133    *
134    * @return The value of this header as a string, or <jk>null</jk> if header was not present.
135    */
136   public String asString() {
137      return getValue();
138   }
139
140   /**
141    * Returns the value of this header as a {@link BasicHeader}.
142    *
143    * @param c The subclass of {@link BasicHeader} to instantiate.
144    * @param <T> The subclass of {@link BasicHeader} to instantiate.
145    * @return The value of this header as a string, never <jk>null</jk>.
146    */
147   public <T extends BasicHeader> T asHeader(Class<T> c) {
148      try {
149         ClassInfo ci = ClassInfo.of(c);
150         ConstructorInfo cc = ci.getConstructor(Visibility.PUBLIC, String.class);
151         if (cc != null)
152            return cc.invoke(asString());
153         cc = ci.getConstructor(Visibility.PUBLIC, String.class, String.class);
154         if (cc != null)
155            return cc.invoke(getName(), asString());
156      } catch (Exception e) {
157         throw new RuntimeException(e);
158      }
159      throw new BasicRuntimeException("Could not determine a method to construct type {0}", c.getClass().getName());
160   }
161
162   /**
163    * Returns the value of this header as a CSV array header.
164    *
165    * @return The value of this header as a CSV array header, never <jk>null</jk>.
166    */
167   public BasicCsvArrayHeader asCsvArrayHeader() {
168      return new BasicCsvArrayHeader(getName(), getValue());
169   }
170
171   /**
172    * Returns the value of this header as a date header.
173    *
174    * @return The value of this header as a date header, never <jk>null</jk>.
175    */
176   public BasicDateHeader asDateHeader() {
177      return new BasicDateHeader(getName(), getValue());
178   }
179
180   /**
181    * Returns the value of this header as an entity validator array header.
182    *
183    * @return The value of this header as an entity validator array header, never <jk>null</jk>.
184    */
185   public BasicEntityTagArrayHeader asEntityTagArrayHeader() {
186      return new BasicEntityTagArrayHeader(getName(), getValue());
187   }
188
189   /**
190    * Returns the value of this header as an entity validator header.
191    *
192    * @return The value of this header as an entity validator array, never <jk>null</jk>.
193    */
194   public BasicEntityTagHeader asEntityTagHeader() {
195      return new BasicEntityTagHeader(getName(), getValue());
196   }
197
198   /**
199    * Returns the value of this header as an integer header.
200    *
201    * @return The value of this header as an integer header, never <jk>null</jk>.
202    */
203   public BasicIntegerHeader asIntegerHeader() {
204      return new BasicIntegerHeader(getName(), getValue());
205   }
206
207   /**
208    * Returns the value of this header as a long header.
209    *
210    * @return The value of this header as a long header, never <jk>null</jk>.
211    */
212   public BasicLongHeader asLongHeader() {
213      return new BasicLongHeader(getName(), getValue());
214   }
215
216   /**
217    * Returns the value of this header as a range array header.
218    *
219    * @return The value of this header as a range array header, never <jk>null</jk>.
220    */
221   public BasicStringRangeArrayHeader asStringRangeArrayHeader() {
222      return new BasicStringRangeArrayHeader(getName(), getValue());
223   }
224
225   /**
226    * Returns the value of this header as a string header.
227    *
228    * @return The value of this header as a string header, never <jk>null</jk>.
229    */
230   public BasicStringHeader asStringHeader() {
231      return new BasicStringHeader(getName(), getValue());
232   }
233
234   /**
235    * Returns the value of this header as a URI header.
236    *
237    * @return The value of this header as a URI header, never <jk>null</jk>.
238    */
239   public BasicUriHeader asUriHeader() {
240      return new BasicUriHeader(getName(), getValue());
241   }
242
243   /**
244    * Same as {@link #asString()} but sets the value in a mutable for fluent calls.
245    *
246    * @param m The mutable to set the header value in.
247    * @return The response object (for method chaining).
248    */
249   public RestResponse asString(Mutable<String> m) {
250      m.set(asString());
251      return response;
252   }
253
254   /**
255    * Returns the value of this header as an {@link Optional}.
256    *
257    * @return The value of this header as an {@link Optional}, or an empty optional if header was not present.
258    */
259   public Optional<String> asOptionalString() {
260      return Optional.ofNullable(getValue());
261   }
262
263   /**
264    * Returns the value of this header as a string with a default value.
265    *
266    * @param def The default value.
267    * @return The value of this header as a string, or the default value if header was not present.
268    */
269   public String asStringOrElse(String def) {
270      return getValue() == null ? def : getValue();
271   }
272
273   /**
274    * Same as {@link #asStringOrElse(String)} but sets the value in a mutable for fluent calls.
275    *
276    * @param m The mutable to set the header value in.
277    * @param def The default value.
278    * @return The response object (for method chaining).
279    */
280   public RestResponse asStringOrElse(Mutable<String> m, String def) {
281      m.set(asStringOrElse(def));
282      return response;
283   }
284
285   /**
286    * Converts this header to the specified type.
287    *
288    * @param <T> The type to convert to.
289    * @param type The type to convert to.
290    * @param args The type parameters.
291    * @return The converted type, or <jk>null</jk> if header is not present.
292    * @throws RestCallException If value could not be parsed.
293    */
294   public <T> T as(Type type, Type...args) throws RestCallException {
295      return as(request.getClassMeta(type, args));
296   }
297
298   /**
299    * Same as {@link #as(Type,Type...)} but sets the value in a mutable for fluent calls.
300    *
301    * @param m The mutable to set the parsed header value in.
302    * @param <T> The type to convert to.
303    * @param type The type to convert to.
304    * @param args The type parameters.
305    * @return The response object (for method chaining).
306    * @throws RestCallException If value could not be parsed.
307    */
308   public <T> RestResponse as(Mutable<T> m, Type type, Type...args) throws RestCallException {
309      m.set(as(type, args));
310      return response;
311   }
312
313   /**
314    * Converts this header to the specified type.
315    *
316    * @param <T> The type to convert to.
317    * @param type The type to convert to.
318    * @return The converted type, or <jk>null</jk> if header is not present.
319    * @throws RestCallException If value could not be parsed.
320    */
321   public <T> T as(Class<T> type) throws RestCallException {
322      return as(request.getClassMeta(type));
323   }
324
325   /**
326    * Same as {@link #as(Class)} but sets the value in a mutable for fluent calls.
327    *
328    * @param m The mutable to set the parsed header value in.
329    * @param <T> The type to convert to.
330    * @param type The type to convert to.
331    * @return The response object (for method chaining).
332    * @throws RestCallException If value could not be parsed.
333    */
334   public <T> RestResponse as(Mutable<T> m, Class<T> type) throws RestCallException {
335      m.set(as(type));
336      return response;
337   }
338
339   /**
340    * Converts this header to the specified type.
341    *
342    * @param <T> The type to convert to.
343    * @param type The type to convert to.
344    * @return The converted type, or <jk>null</jk> if header is not present.
345    * @throws RestCallException If value could not be parsed.
346    */
347   public <T> T as(ClassMeta<T> type) throws RestCallException {
348      try {
349         return parser.parse(HEADER, schema, asString(), type);
350      } catch (ParseException e) {
351         throw new RestCallException(response, e, "Could not parse response header {0}.", getName());
352      }
353   }
354
355   /**
356    * Same as {@link #as(ClassMeta)} but sets the value in a mutable for fluent calls.
357    *
358    * @param m The mutable to set the parsed header value in.
359    * @param <T> The type to convert to.
360    * @param type The type to convert to.
361    * @return The response object (for method chaining).
362    * @throws RestCallException If value could not be parsed.
363    */
364   public <T> RestResponse as(Mutable<T> m, ClassMeta<T> type) throws RestCallException {
365      m.set(as(type));
366      return response;
367   }
368
369   /**
370    * Same as {@link #as(Type,Type...)} but returns the value as an {@link Optional}.
371    *
372    * @param <T> The type to convert to.
373    * @param type The type to convert to.
374    * @param args The type parameters.
375    * @return The parsed value as an {@link Optional}, or an empty optional if header was not present.
376    * @throws RestCallException If value could not be parsed.
377    */
378   public <T> Optional<T> asOptional(Type type, Type...args) throws RestCallException {
379      return Optional.ofNullable(as(type, args));
380   }
381
382   /**
383    * Same as {@link #asOptional(Type,Type...)} but sets the value in a mutable for fluent calls.
384    *
385    * @param m The mutable to set the parsed header value in.
386    * @param <T> The type to convert to.
387    * @param type The type to convert to.
388    * @param args The type parameters.
389    * @return The response object (for method chaining).
390    * @throws RestCallException If value could not be parsed.
391    */
392   public <T> RestResponse asOptional(Mutable<Optional<T>> m, Type type, Type...args) throws RestCallException {
393      m.set(asOptional(type, args));
394      return response;
395   }
396
397   /**
398    * Same as {@link #as(Class)} but returns the value as an {@link Optional}.
399    *
400    * @param <T> The type to convert to.
401    * @param type The type to convert to.
402    * @return The parsed value as an {@link Optional}, or an empty optional if header was not present.
403    * @throws RestCallException If value could not be parsed.
404    */
405   public <T> Optional<T> asOptional(Class<T> type) throws RestCallException {
406      return Optional.ofNullable(as(type));
407   }
408
409   /**
410    * Same as {@link #asOptional(Class)} but sets the value in a mutable for fluent calls.
411    *
412    * @param m The mutable to set the parsed header value in.
413    * @param <T> The type to convert to.
414    * @param type The type to convert to.
415    * @return The response object (for method chaining).
416    * @throws RestCallException If value could not be parsed.
417    */
418   public <T> RestResponse asOptional(Mutable<Optional<T>> m, Class<T> type) throws RestCallException {
419      m.set(asOptional(type));
420      return response;
421   }
422
423   /**
424    * Same as {@link #as(ClassMeta)} but returns the value as an {@link Optional}.
425    *
426    * @param <T> The type to convert to.
427    * @param type The type to convert to.
428    * @return The parsed value as an {@link Optional}, or an empty optional if header was not present.
429    * @throws RestCallException If value could not be parsed.
430    */
431   public <T> Optional<T> asOptional(ClassMeta<T> type) throws RestCallException {
432      return Optional.ofNullable(as(type));
433   }
434
435   /**
436    * Same as {@link #asOptional(ClassMeta)} but sets the value in a mutable for fluent calls.
437    *
438    * @param m The mutable to set the parsed header value in.
439    * @param <T> The type to convert to.
440    * @param type The type to convert to.
441    * @return The response object (for method chaining).
442    * @throws RestCallException If value could not be parsed.
443    */
444   public <T> RestResponse asOptional(Mutable<Optional<T>> m, ClassMeta<T> type) throws RestCallException {
445      m.set(asOptional(type));
446      return response;
447   }
448
449   /**
450    * Matches the specified pattern against this header value.
451    *
452    * <h5 class='section'>Example:</h5>
453    * <p class='bcode w800'>
454    *    <jc>// Parse header using a regular expression.</jc>
455    *    Matcher <jv>matcher</jv> = <jv>client</jv>
456    *       .get(<jsf>URI</jsf>)
457    *       .run()
458    *       .getHeader(<js>"Content-Type"</js>).asMatcher(Pattern.<jsm>compile</jsm>(<js>"application/(.*)"</js>));
459    *
460    *    <jk>if</jk> (<jv>matcher</jv>.matches()) {
461    *       String <jv>mediaType</jv> = <jv>matcher</jv>.group(1);
462    *    }
463    * </p>
464    *
465    * @param pattern The regular expression pattern to match.
466    * @return The matcher.
467    * @throws RestCallException If a connection error occurred.
468    */
469   public Matcher asMatcher(Pattern pattern) throws RestCallException {
470      return pattern.matcher(asStringOrElse(""));
471   }
472
473   /**
474    * Same as {@link #asMatcher(Pattern)} but sets the value in a mutable for fluent calls.
475    *
476    * <h5 class='section'>Example:</h5>
477    * <p class='bcode w800'>
478    *    <jc>// Parse header using a regular expression.</jc>
479    *    Mutable&lt;Matcher&gt; <jv>mutable</jv> = Mutable.<jsm>create</jsm>();
480    *
481    *    <jv>client</jv>
482    *       .get(<jsf>URI</jsf>)
483    *       .run()
484    *       .getHeader(<js>"Content-Type"</js>).asMatcher(<jv>mutable</jv>, Pattern.<jsm>compile</jsm>(<js>"application/(.*)"</js>));
485    *
486    *    <jk>if</jk> (<jv>mutable</jv>.get().matches()) {
487    *       String <jv>mediaType</jv> = <jv>mutable</jv>.get().group(1);
488    *    }
489    * </p>
490    *
491    * @param m The mutable to set the value in.
492    * @param pattern The regular expression pattern to match.
493    * @return The response object (for method chaining).
494    * @throws RestCallException If a connection error occurred.
495    */
496   public RestResponse asMatcher(Mutable<Matcher> m, Pattern pattern) throws RestCallException {
497      m.set(pattern.matcher(asStringOrElse("")));
498      return response;
499   }
500
501   /**
502    * Matches the specified pattern against this header value.
503    *
504    * <h5 class='section'>Example:</h5>
505    * <p class='bcode w800'>
506    *    <jc>// Parse header using a regular expression.</jc>
507    *    Matcher <jv>matcher</jv> = <jv>client</jv>
508    *       .get(<jsf>URI</jsf>)
509    *       .run()
510    *       .getHeader(<js>"Content-Type"</js>).asMatcher(<js>"application/(.*)"</js>);
511    *
512    *    <jk>if</jk> (<jv>matcher</jv>.matches()) {
513    *       String <jv>mediaType</jv> = <jv>matcher</jv>.group(1);
514    *    }
515    * </p>
516    *
517    * @param regex The regular expression pattern to match.
518    * @return The matcher.
519    * @throws RestCallException If a connection error occurred.
520    */
521   public Matcher asMatcher(String regex) throws RestCallException {
522      return asMatcher(regex, 0);
523   }
524
525   /**
526    * Same as {@link #asMatcher(String)} but sets the value in a mutable for fluent calls.
527    *
528    * <h5 class='section'>Example:</h5>
529    * <p class='bcode w800'>
530    *    <jc>// Parse header using a regular expression.</jc>
531    *    Mutable&lt;Matcher&gt; <jv>mutable</jv> = Mutable.<jsm>create</jsm>();
532    *
533    *    <jv>client</jv>
534    *       .get(<jsf>URI</jsf>)
535    *       .run()
536    *       .getHeader(<js>"Content-Type"</js>).asMatcher(<jv>mutable</jv>, <js>"application/(.*)"</js>);
537    *
538    *    <jk>if</jk> (<jv>mutable</jv>.get().matches()) {
539    *       String <jv>mediaType</jv> = <jv>mutable</jv>.get().group(1);
540    *    }
541    * </p>
542    *
543    * @param m The mutable to set the value in.
544    * @param regex The regular expression pattern to match.
545    * @return The response object (for method chaining).
546    * @throws RestCallException If a connection error occurred.
547    */
548   public RestResponse asMatcher(Mutable<Matcher> m, String regex) throws RestCallException {
549      m.set(asMatcher(regex, 0));
550      return response;
551   }
552
553   /**
554    * Matches the specified pattern against this header value.
555    *
556    * <h5 class='section'>Example:</h5>
557    * <p class='bcode w800'>
558    *    <jc>// Parse header using a regular expression.</jc>
559    *    Matcher <jv>matcher</jv> = <jv>client</jv>
560    *       .get(<jsf>URI</jsf>)
561    *       .run()
562    *       .getHeader(<js>"Content-Type"</js>).asMatcher(<js>"application/(.*)"</js>, <jsf>CASE_INSENSITIVE</jsf>);
563    *
564    *    <jk>if</jk> (<jv>matcher</jv>.matches()) {
565    *       String <jv>mediaType</jv> = <jv>matcher</jv>.group(1);
566    *    }
567    * </p>
568    *
569    * @param regex The regular expression pattern to match.
570    * @param flags Pattern match flags.  See {@link Pattern#compile(String, int)}.
571    * @return The matcher.
572    * @throws RestCallException If a connection error occurred.
573    */
574   public Matcher asMatcher(String regex, int flags) throws RestCallException {
575      return asMatcher(Pattern.compile(regex, flags));
576   }
577
578   /**
579    * Same as {@link #asMatcher(String,int)} but sets the value in a mutable for fluent calls.
580    *
581    * <h5 class='section'>Example:</h5>
582    * <p class='bcode w800'>
583    *    <jc>// Parse header using a regular expression.</jc>
584    *    Mutable&lt;Matcher&gt; <jv>mutable</jv> = Mutable.<jsm>create</jsm>();
585    *
586    *    client
587    *       .get(<jsf>URI</jsf>)
588    *       .run()
589    *       .getHeader(<js>"Content-Type"</js>).asMatcher(<jv>mutable</jv>, <js>"application/(.*)"</js>, <jsf>CASE_INSENSITIVE</jsf>);
590    *
591    *    <jk>if</jk> (<jv>mutable</jv>.get().matches()) {
592    *       String <jv>mediaType</jv> = <jv>mutable</jv>.get().group(1);
593    *    }
594    * </p>
595    *
596    * @param m The mutable to set the value in.
597    * @param regex The regular expression pattern to match.
598    * @param flags Pattern match flags.  See {@link Pattern#compile(String, int)}.
599    * @return The response object (for method chaining).
600    * @throws RestCallException If a connection error occurred.
601    */
602   public RestResponse asMatcher(Mutable<Matcher> m, String regex, int flags) throws RestCallException {
603      m.set(asMatcher(Pattern.compile(regex, flags)));
604      return response;
605   }
606
607   /**
608    * Returns the response that created this object.
609    *
610    * @return The response that created this object.
611    */
612   public RestResponse toResponse() {
613      return response;
614   }
615
616   //------------------------------------------------------------------------------------------------------------------
617   // Assertions.
618   //------------------------------------------------------------------------------------------------------------------
619
620   /**
621    * Provides the ability to perform fluent-style assertions on this response header.
622    *
623    * <p>
624    * This method is called directly from the {@link RestResponse#assertStringHeader(String)} method to instantiate a fluent assertions object.
625    *
626    * <h5 class='section'>Examples:</h5>
627    * <p class='bcode w800'>
628    *    <jc>// Validates the content type header is provided.</jc>
629    *    <jv>client</jv>
630    *       .get(<jsf>URI</jsf>)
631    *       .run()
632    *       .assertHeader(<js>"Content-Type"</js>).exists();
633    *
634    *    <jc>// Validates the content type is JSON.</jc>
635    *    <jv>client</jv>
636    *       .get(<jsf>URI</jsf>)
637    *       .run()
638    *       .assertHeader(<js>"Content-Type"</js>).equals(<js>"application/json"</js>);
639    *
640    *    <jc>// Validates the content type is JSON using test predicate.</jc>
641    *    <jv>client</jv>
642    *       .get(<jsf>URI</jsf>)
643    *       .run()
644    *       .assertHeader(<js>"Content-Type"</js>).passes(<jv>x</jv> -&gt; <jv>x</jv>.equals(<js>"application/json"</js>));
645    *
646    *    <jc>// Validates the content type is JSON by just checking for substring.</jc>
647    *    <jv>client</jv>
648    *       .get(<jsf>URI</jsf>)
649    *       .run()
650    *       .assertHeader(<js>"Content-Type"</js>).contains(<js>"json"</js>);
651    *
652    *    <jc>// Validates the content type is JSON using regular expression.</jc>
653    *    <jv>client</jv>
654    *       .get(<jsf>URI</jsf>)
655    *       .run()
656    *       .assertHeader(<js>"Content-Type"</js>).matches(<js>".*json.*"</js>);
657    *
658    *    <jc>// Validates the content type is JSON using case-insensitive regular expression.</jc>
659    *    <jv>client</jv>
660    *       .get(<jsf>URI</jsf>)
661    *       .run()
662    *       .assertHeader(<js>"Content-Type"</js>).matches(<js>".*json.*"</js>, <jsf>CASE_INSENSITIVE</jsf>);
663    * </p>
664    *
665    * <p>
666    * The assertion test returns the original response object allowing you to chain multiple requests like so:
667    * <p class='bcode w800'>
668    *    <jc>// Validates the header and converts it to a bean.</jc>
669    *    MediaType <jv>mediaType</jv> = <jv>client</jv>
670    *       .get(<jsf>URI</jsf>)
671    *       .run()
672    *       .assertHeader(<js>"Content-Type"</js>).exists()
673    *       .assertHeader(<js>"Content-Type"</js>).matches(<js>".*json.*"</js>)
674    *       .getHeader(<js>"Content-Type"</js>).as(MediaType.<jk>class</jk>);
675    * </p>
676    *
677    * @return A new fluent assertion object.
678    */
679   public FluentStringAssertion<RestResponse> assertString() {
680      return new FluentStringAssertion<>(asString(), response);
681   }
682
683   /**
684    * Provides the ability to perform fluent-style assertions on an integer response header.
685    *
686    * <p>
687    * This method is called directly from the {@link RestResponse#assertIntegerHeader(String)} method to instantiate a fluent assertions object.
688    *
689    * <h5 class='section'>Examples:</h5>
690    * <p class='bcode w800'>
691    *    <jc>// Validates that the response content age is greater than 1.</jc>
692    *    <jv>client</jv>
693    *       .get(<jsf>URI</jsf>)
694    *       .run()
695    *       .assertIntegerHeader(<js>"Age"</js>).isGreaterThan(1);
696    * </p>
697    *
698    * @return A new fluent assertion object.
699    */
700   public FluentIntegerAssertion<RestResponse> assertInteger() {
701      return new FluentIntegerAssertion<>(asIntegerHeader().asInt(), response);
702   }
703
704   /**
705    * Provides the ability to perform fluent-style assertions on a long response header.
706    *
707    * <p>
708    * This method is called directly from the {@link RestResponse#assertLongHeader(String)} method to instantiate a fluent assertions object.
709    *
710    * <h5 class='section'>Examples:</h5>
711    * <p class='bcode w800'>
712    *    <jc>// Validates that the response body is not too long.</jc>
713    *    <jv>client</jv>
714    *       .get(<jsf>URI</jsf>)
715    *       .run()
716    *       .assertLongHeader(<js>"Length"</js>).isLessThan(100000);
717    * </p>
718    *
719    * @return A new fluent assertion object.
720    */
721   public FluentLongAssertion<RestResponse> assertLong() {
722      return new FluentLongAssertion<>(asLongHeader().asLong(), response);
723   }
724
725   /**
726    * Provides the ability to perform fluent-style assertions on a date response header.
727    *
728    * <p>
729    * This method is called directly from the {@link RestResponse#assertDateHeader(String)} method to instantiate a fluent assertions object.
730    *
731    * <h5 class='section'>Examples:</h5>
732    * <p class='bcode w800'>
733    *    <jc>// Validates that the response content is not expired.</jc>
734    *    <jv>client</jv>
735    *       .get(<jsf>URI</jsf>)
736    *       .run()
737    *       .getHeader(<js>"Expires"</js>).assertDate().isAfterNow();
738    * </p>
739    *
740    * @return A new fluent assertion object.
741    */
742   public FluentZonedDateTimeAssertion<RestResponse> assertDate() {
743      return new FluentZonedDateTimeAssertion<>(asDateHeader().asZonedDateTime(), response);
744   }
745
746   /**
747    * Provides the ability to perform fluent-style assertions on comma-separated string headers.
748    *
749    * <p>
750    * This method is called directly from the {@link RestResponse#assertCsvArrayHeader(String)} method to instantiate a fluent assertions object.
751    *
752    * <h5 class='section'>Examples:</h5>
753    * <p class='bcode w800'>
754    *    <jc>// Validates that the response content is not expired.</jc>
755    *    <jv>client</jv>
756    *       .get(<jsf>URI</jsf>)
757    *       .run()
758    *       .getHeader(<js>"Allow"</js>).assertCsvArray().contains(<js>"GET"</js>);
759    * </p>
760    *
761    * @return A new fluent assertion object.
762    */
763   public FluentListAssertion<RestResponse> assertCsvArray() {
764      return new FluentListAssertion<>(asCsvArrayHeader().asList(), response);
765   }
766
767   //------------------------------------------------------------------------------------------------------------------
768   // Header passthrough methods.
769   //------------------------------------------------------------------------------------------------------------------
770
771   /**
772    * Gets the name of this pair.
773    *
774    * @return The name of this pair, never <jk>null</jk>.
775    */
776   @Override /* Header */
777   public String getName() {
778      return header.getName();
779   }
780
781   /**
782    * Gets the value of this pair.
783    *
784    * <ul class='notes'>
785    *    <li>{@link #asString()} is an equivalent method and the preferred method for fluent-style coding.
786    * </ul>
787    *
788    * @return The value of this pair, may be <jk>null</jk>.
789    */
790   @Override /* Header */
791   public String getValue() {
792      return header.getValue();
793   }
794
795   /**
796    * Parses the value.
797    *
798    * @return An array of {@link HeaderElement} entries, may be empty, but is never <jk>null</jk>.
799    * @throws org.apache.http.ParseException In case of a parsing error.
800    */
801   @Override /* Header */
802   public HeaderElement[] getElements() throws org.apache.http.ParseException {
803      return header.getElements();
804   }
805
806   @Override /* Object */
807   public String toString() {
808      return getName() + ": " + getValue();
809   }
810}