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<Matcher> <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<Matcher> <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<Matcher> <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> -> <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}