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.http.header; 014 015import static org.apache.juneau.common.internal.ArgUtils.*; 016import static org.apache.juneau.common.internal.StringUtils.*; 017import static org.apache.juneau.internal.CollectionUtils.*; 018import static org.apache.juneau.internal.ConsumerUtils.*; 019 020import java.util.*; 021import java.util.function.*; 022import java.util.stream.*; 023 024import org.apache.http.*; 025import org.apache.http.util.*; 026import org.apache.juneau.collections.*; 027import org.apache.juneau.common.internal.*; 028import org.apache.juneau.http.HttpHeaders; 029import org.apache.juneau.internal.*; 030import org.apache.juneau.svl.*; 031 032/** 033 * A simple list of HTTP headers with various convenience methods. 034 * 035 * <h5 class='figure'>Example</h5> 036 * <p class='bjava'> 037 * HeaderList <jv>headers</jv> = HeaderList 038 * .<jsm>create</jsm>() 039 * .append(Accept.<jsm>of</jsm>(<js>"text/xml"</js>)) 040 * .append(<js>"Content-Type"</js>, ()-><jsm>getDynamicContentTypeFromSomewhere</jsm>()); 041 * </p> 042 * 043 * <p> 044 * Convenience creators are provided for creating lists with minimal code: 045 * <p class='bjava'> 046 * HeaderList <jv>headers</jv> = HeaderList.<jsm>of</jsm>(Accept.<jsf>TEXT_XML</jsf>, ContentType.<jsf>TEXT_XML</jsf>); 047 * </p> 048 * 049 * <p> 050 * Static methods are provided on {@link HttpHeaders} to further simplify creation of header lists. 051 * <p class='bjava'> 052 * <jk>import static</jk> org.apache.juneau.http.HttpHeaders.*; 053 * 054 * HeaderList <jv>headers</jv> = <jsm>headerList</jsm>(<jsm>accept</jsm>(<js>"text/xml"</js>), <jsm>contentType</jsm>(<js>"text/xml"</js>)); 055 * </p> 056 * 057 * <h5 class='section'>See Also:</h5><ul> 058 * <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-common">juneau-rest-common</a> 059 * </ul> 060 */ 061@FluentSetters 062public class HeaderList extends ControlledArrayList<Header> { 063 064 private static final long serialVersionUID = 1L; 065 066 //----------------------------------------------------------------------------------------------------------------- 067 // Static 068 //----------------------------------------------------------------------------------------------------------------- 069 070 /** Represents no header list in annotations. */ 071 public static final class Void extends HeaderList { 072 private static final long serialVersionUID = 1L; 073 } 074 075 /** 076 * Instantiates a new list. 077 * 078 * @return A new list. 079 */ 080 public static HeaderList create() { 081 return new HeaderList(); 082 } 083 084 /** 085 * Creates a new {@link HeaderList} initialized with the specified headers. 086 * 087 * @param headers 088 * The headers to add to the list. 089 * <br>Can be <jk>null</jk>. 090 * <br><jk>null</jk> entries are ignored. 091 * @return A new unmodifiable instance, never <jk>null</jk>. 092 */ 093 public static HeaderList of(List<Header> headers) { 094 return new HeaderList().append(headers); 095 } 096 097 /** 098 * Creates a new {@link HeaderList} initialized with the specified headers. 099 * 100 * @param headers 101 * The headers to add to the list. 102 * <br><jk>null</jk> entries are ignored. 103 * @return A new unmodifiable instance, never <jk>null</jk>. 104 */ 105 public static HeaderList of(Header...headers) { 106 return new HeaderList().append(headers); 107 } 108 109 /** 110 * Creates a new {@link HeaderList} initialized with the specified name/value pairs. 111 * 112 * <h5 class='figure'>Example</h5> 113 * <p class='bjava'> 114 * HeaderList <jv>headers</jv> = HeaderList.<jsm>ofPairs</jsm>(<js>"Accept"</js>, <js>"text/xml"</js>, <js>"Content-Type"</js>, <js>"text/xml"</js>); 115 * </p> 116 * 117 * @param pairs 118 * Initial list of pairs. 119 * <br>Must be an even number of parameters representing key/value pairs. 120 * @throws RuntimeException If odd number of parameters were specified. 121 * @return A new instance. 122 */ 123 public static HeaderList ofPairs(String... pairs) { 124 HeaderList x = new HeaderList(); 125 if (pairs == null) 126 pairs = new String[0]; 127 if (pairs.length % 2 != 0) 128 throw new IllegalArgumentException("Odd number of parameters passed into HeaderList.ofPairs()"); 129 for (int i = 0; i < pairs.length; i+=2) 130 x.add(BasicHeader.of(pairs[i], pairs[i+1])); 131 return x; 132 } 133 134 //----------------------------------------------------------------------------------------------------------------- 135 // Instance 136 //----------------------------------------------------------------------------------------------------------------- 137 138 private VarResolver varResolver; 139 boolean caseSensitive; 140 141 /** 142 * Constructor. 143 */ 144 public HeaderList() { 145 super(false); 146 } 147 148 /** 149 * Copy constructor. 150 * 151 * @param copyFrom The bean to copy. 152 */ 153 protected HeaderList(HeaderList copyFrom) { 154 super(false, copyFrom); 155 caseSensitive = copyFrom.caseSensitive; 156 } 157 158 /** 159 * Makes a copy of this list. 160 * 161 * @return A new copy of this list. 162 */ 163 public HeaderList copy() { 164 return new HeaderList(this); 165 } 166 167 /** 168 * Adds a collection of default headers. 169 * 170 * <p> 171 * Default headers are set if they're not already in the list. 172 * 173 * @param headers The list of default headers. 174 * @return This object. 175 */ 176 public HeaderList setDefault(List<Header> headers) { 177 if (headers != null) 178 headers.stream().filter(x -> x != null && ! contains(x.getName())).forEach(this::set); 179 return this; 180 } 181 182 /** 183 * Replaces the first occurrence of the headers with the same name. 184 * 185 * @param name The header name. 186 * @param value The header value. 187 * @return This object. 188 */ 189 public HeaderList setDefault(String name, Object value) { 190 return setDefault(createPart(name, value)); 191 } 192 193 /** 194 * Replaces the first occurrence of the headers with the same name. 195 * 196 * @param name The header name. 197 * @param value The header value. 198 * @return This object. 199 */ 200 public HeaderList setDefault(String name, Supplier<?> value) { 201 return setDefault(createPart(name, value)); 202 } 203 204 /** 205 * Makes a copy of this list of headers and adds a collection of default headers. 206 * 207 * <p> 208 * Default headers are set if they're not already in the list. 209 * 210 * @param headers The list of default headers. 211 * @return A new list, or the same list if the headers were empty. 212 */ 213 public HeaderList setDefault(Header...headers) { 214 if (headers != null) 215 setDefault(Arrays.asList(headers)); 216 return this; 217 } 218 219 220 //------------------------------------------------------------------------------------------------------------- 221 // Properties 222 //------------------------------------------------------------------------------------------------------------- 223 224 /** 225 * Allows header values to contain SVL variables. 226 * 227 * <p> 228 * Resolves variables in header values when using the following methods: 229 * <ul> 230 * <li class='jm'>{@link #append(String, Object) append(String,Object)} 231 * <li class='jm'>{@link #append(String, Supplier) append(String,Supplier<?>)} 232 * <li class='jm'>{@link #prepend(String, Object) prepend(String,Object)} 233 * <li class='jm'>{@link #prepend(String, Supplier) prepend(String,Supplier<?>)} 234 * <li class='jm'>{@link #set(String, Object) set(String,Object)} 235 * <li class='jm'>{@link #set(String, Supplier) set(String,Supplier<?>)} 236 * </ul> 237 * 238 * <p> 239 * Uses {@link VarResolver#DEFAULT} to resolve variables. 240 * 241 * @return This object. 242 */ 243 public HeaderList resolving() { 244 return resolving(VarResolver.DEFAULT); 245 } 246 247 /** 248 * Allows header values to contain SVL variables. 249 * 250 * <p> 251 * Resolves variables in header values when using the following methods: 252 * <ul> 253 * <li class='jm'>{@link #append(String, Object) append(String,Object)} 254 * <li class='jm'>{@link #append(String, Supplier) append(String,Supplier<?>)} 255 * <li class='jm'>{@link #prepend(String, Object) prepend(String,Object)} 256 * <li class='jm'>{@link #prepend(String, Supplier) prepend(String,Supplier<?>)} 257 * <li class='jm'>{@link #set(String, Object) set(String,Object)} 258 * <li class='jm'>{@link #set(String, Supplier) set(String,Supplier<?>)} 259 * </ul> 260 * 261 * @param varResolver The variable resolver to use for resolving variables. 262 * @return This object. 263 */ 264 public HeaderList resolving(VarResolver varResolver) { 265 assertModifiable(); 266 this.varResolver = varResolver; 267 return this; 268 } 269 270 /** 271 * Specifies that the headers in this list should be treated as case-sensitive. 272 * 273 * <p> 274 * The default behavior is case-insensitive. 275 * 276 * @param value The new value for this setting. 277 * @return This object. 278 */ 279 public HeaderList caseSensitive(boolean value) { 280 assertModifiable(); 281 caseSensitive = value; 282 return this; 283 } 284 285 /** 286 * Adds the specified header to the end of the headers in this list. 287 * 288 * @param value The header to add. <jk>null</jk> values are ignored. 289 * @return This object. 290 */ 291 @FluentSetter 292 public HeaderList append(Header value) { 293 if (value != null) 294 add(value); 295 return this; 296 } 297 298 /** 299 * Appends the specified header to the end of this list. 300 * 301 * <p> 302 * The header is added as a {@link BasicHeader}. 303 * 304 * @param name The header name. 305 * @param value The header value. 306 * @return This object. 307 */ 308 public HeaderList append(String name, Object value) { 309 return append(createPart(name, value)); 310 } 311 312 /** 313 * Appends the specified header to the end of this list using a value supplier. 314 * 315 * <p> 316 * The header is added as a {@link BasicHeader}. 317 * 318 * <p> 319 * Value is re-evaluated on each call to {@link BasicHeader#getValue()}. 320 * 321 * @param name The header name. 322 * @param value The header value supplier. 323 * @return This object. 324 */ 325 public HeaderList append(String name, Supplier<?> value) { 326 return append(createPart(name, value)); 327 } 328 329 /** 330 * Adds the specified headers to the end of the headers in this list. 331 * 332 * @param values The headers to add. <jk>null</jk> values are ignored. 333 * @return This object. 334 */ 335 @FluentSetter 336 public HeaderList append(Header...values) { 337 if (values != null) 338 for (Header value : values) 339 if (value != null) 340 append(value); 341 return this; 342 } 343 344 /** 345 * Adds the specified headers to the end of the headers in this list. 346 * 347 * @param values The headers to add. <jk>null</jk> values are ignored. 348 * @return This object. 349 */ 350 @FluentSetter 351 public HeaderList append(List<Header> values) { 352 if (values != null) 353 values.forEach(this::append); 354 return this; 355 } 356 357 /** 358 * Adds the specified header to the beginning of the headers in this list. 359 * 360 * @param value The header to add. <jk>null</jk> values are ignored. 361 * @return This object. 362 */ 363 @FluentSetter 364 public HeaderList prepend(Header value) { 365 if (value != null) 366 add(0, value); 367 return this; 368 } 369 370 /** 371 * Appends the specified header to the beginning of this list. 372 * 373 * <p> 374 * The header is added as a {@link BasicHeader}. 375 * 376 * @param name The header name. 377 * @param value The header value. 378 * @return This object. 379 */ 380 public HeaderList prepend(String name, Object value) { 381 return prepend(createPart(name, value)); 382 } 383 384 /** 385 * Appends the specified header to the beginning of this list using a value supplier. 386 * 387 * <p> 388 * The header is added as a {@link BasicHeader}. 389 * 390 * <p> 391 * Value is re-evaluated on each call to {@link BasicHeader#getValue()}. 392 * 393 * @param name The header name. 394 * @param value The header value supplier. 395 * @return This object. 396 */ 397 public HeaderList prepend(String name, Supplier<?> value) { 398 return prepend(createPart(name, value)); 399 } 400 401 /** 402 * Adds the specified headers to the beginning of the headers in this list. 403 * 404 * @param values The headers to add. <jk>null</jk> values are ignored. 405 * @return This object. 406 */ 407 @FluentSetter 408 public HeaderList prepend(Header...values) { 409 if (values != null) 410 prepend(alist(values)); 411 return this; 412 } 413 414 /** 415 * Adds the specified headers to the beginning of the headers in this list. 416 * 417 * @param values The headers to add. <jk>null</jk> values are ignored. 418 * @return This object. 419 */ 420 @FluentSetter 421 public HeaderList prepend(List<Header> values) { 422 if (values != null) 423 addAll(0, values); 424 return this; 425 } 426 427 /** 428 * Removes the specified header from this list. 429 * 430 * @param value The header to remove. <jk>null</jk> values are ignored. 431 * @return This object. 432 */ 433 @FluentSetter 434 public HeaderList remove(Header value) { 435 if (value != null) 436 removeIf(x -> eq(x.getName(), value.getName()) && eq(x.getValue(), value.getValue())); 437 return this; 438 } 439 440 /** 441 * Removes the specified headers from this list. 442 * 443 * @param values The headers to remove. <jk>null</jk> values are ignored. 444 * @return This object. 445 */ 446 @FluentSetter 447 public HeaderList remove(Header...values) { 448 for (Header value : values) 449 remove(value); 450 return this; 451 } 452 453 /** 454 * Removes the specified headers from this list. 455 * 456 * @param values The headers to remove. <jk>null</jk> values are ignored. 457 * @return This object. 458 */ 459 @FluentSetter 460 public HeaderList remove(List<Header> values) { 461 if (values != null) 462 values.forEach(this::remove); 463 return this; 464 } 465 466 /** 467 * Removes the header with the specified name from this list. 468 * 469 * @param name The header name. 470 * @return This object. 471 */ 472 @FluentSetter 473 public HeaderList remove(String name) { 474 removeIf(x -> eq(x.getName(), name)); 475 return this; 476 } 477 478 /** 479 * Removes the header with the specified name from this list. 480 * 481 * @param names The header name. 482 * @return This object. 483 */ 484 @FluentSetter 485 public HeaderList remove(String...names) { 486 if (names != null) 487 for (String name : names) 488 remove(name); 489 return this; 490 } 491 492 /** 493 * Removes all headers from this list. 494 * 495 * @return This object. 496 */ 497 public HeaderList removeAll() { 498 clear(); 499 return this; 500 } 501 502 /** 503 * Adds or replaces the header(s) with the same name. 504 * 505 * <p> 506 * If no header with the same name is found the given header is added to the end of the list. 507 * 508 * @param value The headers to replace. <jk>null</jk> values are ignored. 509 * @return This object. 510 */ 511 @FluentSetter 512 public HeaderList set(Header value) { 513 if (value != null) { 514 boolean replaced = false; 515 for (int i = 0, j = size(); i < j; i++) { 516 Header x = get(i); 517 if (eq(x.getName(), value.getName())) { 518 if (replaced) { 519 remove(i); 520 j--; 521 } else { 522 set(i, value); 523 replaced = true; 524 } 525 } 526 } 527 528 if (! replaced) 529 add(value); 530 } 531 532 return this; 533 } 534 535 /** 536 * Adds or replaces the header(s) with the same name. 537 * 538 * <p> 539 * If no header with the same name is found the given header is added to the end of the list. 540 * 541 * @param values The headers to replace. <jk>null</jk> values are ignored. 542 * @return This object. 543 */ 544 @FluentSetter 545 public HeaderList set(Header...values) { 546 if (values != null) 547 set(alist(values)); 548 return this; 549 } 550 551 /** 552 * Replaces the first occurrence of the headers with the same name. 553 * 554 * @param name The header name. 555 * @param value The header value. 556 * @return This object. 557 */ 558 public HeaderList set(String name, Object value) { 559 return set(createPart(name, value)); 560 } 561 562 /** 563 * Replaces the first occurrence of the headers with the same name. 564 * 565 * @param name The header name. 566 * @param value The header value. 567 * @return This object. 568 */ 569 public HeaderList set(String name, Supplier<?> value) { 570 return set(createPart(name, value)); 571 } 572 573 /** 574 * Replaces the first occurrence of the headers with the same name. 575 * 576 * <p> 577 * If no header with the same name is found the given header is added to the end of the list. 578 * 579 * @param values The headers to replace. <jk>null</jk> values are ignored. 580 * @return This object. 581 */ 582 @FluentSetter 583 public HeaderList set(List<Header> values) { 584 585 if (values != null) { 586 for (Header h : values) { 587 if (h != null) { 588 for (int i2 = 0, j2 = size(); i2 < j2; i2++) { 589 Header x = get(i2); 590 if (eq(x.getName(), h.getName())) { 591 remove(i2); 592 j2--; 593 } 594 } 595 } 596 } 597 598 for (Header x : values) { 599 if (x != null) { 600 add(x); 601 } 602 } 603 } 604 605 return this; 606 } 607 608 /** 609 * Gets the first header with the given name. 610 * 611 * <p> 612 * Header name comparison is case insensitive. 613 * 614 * @param name The header name. 615 * @return The first matching header, or {@link Optional#empty()} if not found. 616 */ 617 public Optional<Header> getFirst(String name) { 618 for (int i = 0; i < size(); i++) { 619 Header x = get(i); 620 if (eq(x.getName(), name)) 621 return optional(x); 622 } 623 return empty(); 624 } 625 626 /** 627 * Gets the last header with the given name. 628 * 629 * <p> 630 * Header name comparison is case insensitive. 631 * 632 * @param name The header name. 633 * @return The last matching header, or {@link Optional#empty()} if not found. 634 */ 635 public Optional<Header> getLast(String name) { 636 for (int i = size() - 1; i >= 0; i--) { 637 Header x = get(i); 638 if (eq(x.getName(), name)) 639 return optional(x); 640 } 641 return empty(); 642 } 643 644 /** 645 * Gets a header representing all of the header values with the given name. 646 * 647 * <p> 648 * If more that one header with the given name exists the values will be combined with <js>", "</js> as per 649 * <a href='https://tools.ietf.org/html/rfc2616#section-4.2'>RFC 2616 Section 4.2</a>. 650 * 651 * @param name The header name. 652 * @return A header with a condensed value, or {@link Optional#empty()} if no headers by the given name are present 653 */ 654 public Optional<Header> get(String name) { 655 656 Header first = null; 657 List<Header> rest = null; 658 for (Header x : this) { 659 if (eq(x.getName(), name)) { 660 if (first == null) 661 first = x; 662 else { 663 if (rest == null) 664 rest = list(); 665 rest.add(x); 666 } 667 } 668 } 669 670 if (first == null) 671 return empty(); 672 673 if (rest == null) 674 return optional(first); 675 676 CharArrayBuffer sb = new CharArrayBuffer(128); 677 sb.append(first.getValue()); 678 for (Header element : rest) { 679 sb.append(", "); 680 sb.append(element.getValue()); 681 } 682 683 return optional(new BasicHeader(name, sb.toString())); 684 } 685 686 /** 687 * Gets a header representing all of the header values with the given name. 688 * 689 * <p> 690 * If more that one header with the given name exists the values will be combined with <js>", "</js> as per 691 * <a href='https://tools.ietf.org/html/rfc2616#section-4.2'>RFC 2616 Section 4.2</a>. 692 * 693 * <p> 694 * The implementation class must have a public constructor taking in one of the following argument lists: 695 * <ul> 696 * <li><c>X(String <jv>value</jv>)</c> 697 * <li><c>X(Object <jv>value</jv>)</c> 698 * <li><c>X(String <jv>name</jv>, String <jv>value</jv>)</c> 699 * <li><c>X(String <jv>name</jv>, Object <jv>value</jv>)</c> 700 * </ul> 701 * 702 * <h5 class='figure'>Example</h5> 703 * <p class='bjava'> 704 * BasicIntegerHeader <jv>age</jv> = headerList.get(<js>"Age"</js>, BasicIntegerHeader.<jk>class</jk>); 705 * </p> 706 * 707 * @param <T> The header implementation class. 708 * @param name The header name. 709 * @param type The header implementation class. 710 * @return A header with a condensed value or <jk>null</jk> if no headers by the given name are present 711 */ 712 public <T> Optional<T> get(String name, Class<T> type) { 713 714 Header first = null; 715 List<Header> rest = null; 716 for (Header x : this) { 717 if (eq(x.getName(), name)) { 718 if (first == null) 719 first = x; 720 else { 721 if (rest == null) 722 rest = list(); 723 rest.add(x); 724 } 725 } 726 } 727 728 if (first == null) 729 return empty(); 730 731 if (rest == null) 732 return optional(HeaderBeanMeta.of(type).construct(name, first.getValue())); 733 734 CharArrayBuffer sb = new CharArrayBuffer(128); 735 sb.append(first.getValue()); 736 for (Header element : rest) { 737 sb.append(", "); 738 sb.append(element.getValue()); 739 } 740 741 return optional(HeaderBeanMeta.of(type).construct(name, sb.toString())); 742 } 743 744 /** 745 * Gets a header representing all of the header values with the given name. 746 * 747 * <p> 748 * Same as {@link #get(String, Class)} but the header name is pulled from the {@link org.apache.juneau.http.annotation.Header#name()} or 749 * {@link org.apache.juneau.http.annotation.Header#value()} annotations. 750 * 751 * <h5 class='figure'>Example</h5> 752 * <p class='bjava'> 753 * Age <jv>age</jv> = headerList.get(Age.<jk>class</jk>); 754 * </p> 755 * 756 * @param <T> The return type. 757 * @param type The header implementation class. 758 * @return A header with a condensed value or <jk>null</jk> if no headers by the given name are present 759 */ 760 public <T> Optional<T> get(Class<T> type) { 761 assertArgNotNull("type", type); 762 763 String name = HeaderBeanMeta.of(type).getSchema().getName(); 764 assertArg(name != null, "Header name could not be found on bean type ''{0}''", type.getName()); 765 766 return get(name, type); 767 } 768 769 /** 770 * Gets all of the headers. 771 * 772 * <p> 773 * The returned array maintains the relative order in which the headers were added. 774 * Each call creates a new array not backed by this list. 775 * 776 * <p> 777 * As a general rule, it's more efficient to use the other methods with consumers to 778 * get headers. 779 * 780 * @return An array containing all headers, never <jk>null</jk>. 781 */ 782 public Header[] getAll() { 783 return stream().toArray(Header[]::new); 784 } 785 786 /** 787 * Gets all of the headers with the given name. 788 * 789 * <p> 790 * The returned array maintains the relative order in which the headers were added. 791 * Header name comparison is case insensitive. 792 * Headers with null values are ignored. 793 * Each call creates a new array not backed by this list. 794 * 795 * <p> 796 * As a general rule, it's more efficient to use the other methods with consumers to 797 * get headers. 798 * 799 * @param name The header name. 800 * 801 * @return An array containing all matching headers, never <jk>null</jk>. 802 */ 803 public Header[] getAll(String name) { 804 return stream().filter(x -> eq(x.getName(), name)).toArray(Header[]::new); 805 } 806 807 /** 808 * Performs an action on the values for all matching headers in this list. 809 * 810 * @param filter A predicate to apply to each element to determine if it should be included. Can be <jk>null</jk>. 811 * @param action An action to perform on each element. 812 * @return This object. 813 */ 814 public HeaderList forEachValue(Predicate<Header> filter, Consumer<String> action) { 815 return forEach(filter, x -> action.accept(x.getValue())); 816 } 817 818 /** 819 * Performs an action on the values of all matching headers in this list. 820 * 821 * @param name The header name. 822 * @param action An action to perform on each element. 823 * @return This object. 824 */ 825 public HeaderList forEachValue(String name, Consumer<String> action) { 826 return forEach(name, x -> action.accept(x.getValue())); 827 } 828 829 /** 830 * Returns all the string values for all headers with the specified name. 831 * 832 * @param name The header name. 833 * @return An array containing all values. Never <jk>null</jk>. 834 */ 835 public String[] getValues(String name) { 836 return stream().filter(x -> eq(x.getName(), name)).map(Header::getValue).toArray(String[]::new); 837 } 838 839 /** 840 * Tests if headers with the given name are contained within this list. 841 * 842 * <p> 843 * Header name comparison is case insensitive. 844 * 845 * @param name The header name. 846 * @return <jk>true</jk> if at least one header with the name is present. 847 */ 848 public boolean contains(String name) { 849 return stream().anyMatch(x -> eq(x.getName(), name)); 850 } 851 852 /** 853 * Returns an iterator over this list of headers. 854 * 855 * @return A new iterator over this list of headers. 856 */ 857 public HeaderIterator headerIterator() { 858 return new BasicHeaderIterator(toArray(new Header[0]), null, caseSensitive); 859 } 860 861 /** 862 * Returns an iterator over the headers with a given name in this list. 863 * 864 * @param name The name of the headers over which to iterate, or <jk>null</jk> for all headers 865 * 866 * @return A new iterator over the matching headers in this list. 867 */ 868 public HeaderIterator headerIterator(String name) { 869 return new BasicHeaderIterator(getAll(name), name, caseSensitive); 870 } 871 872 /** 873 * Performs an action on all headers with the specified name in this list. 874 * 875 * <p> 876 * This is the preferred method for iterating over headers as it does not involve 877 * creation or copy of lists/arrays. 878 * 879 * @param name The header name. 880 * @param action An action to perform on each element. 881 * @return This object. 882 */ 883 public HeaderList forEach(String name, Consumer<Header> action) { 884 return forEach(x -> eq(name, x.getName()), action); 885 } 886 887 /** 888 * Performs an action on all matching headers in this list. 889 * 890 * <p> 891 * This is the preferred method for iterating over headers as it does not involve 892 * creation or copy of lists/arrays. 893 * 894 * @param filter A predicate to apply to each element to determine if it should be included. Can be <jk>null</jk>. 895 * @param action An action to perform on each element. 896 * @return This object. 897 */ 898 public HeaderList forEach(Predicate<Header> filter, Consumer<Header> action) { 899 forEach(x -> consume(filter, action, x)); 900 return this; 901 } 902 903 /** 904 * Returns a stream of the headers in this list with the specified name. 905 * 906 * <p> 907 * This does not involve a copy of the underlying array of <c>Header</c> objects so should perform well. 908 * 909 * @param name The header name. 910 * @return This object. 911 */ 912 public Stream<Header> stream(String name) { 913 return stream().filter(x->eq(name, x.getName())); 914 } 915 916 //------------------------------------------------------------------------------------------------------------- 917 // Other methods 918 //------------------------------------------------------------------------------------------------------------- 919 920 /** 921 * Creates a new header out of the specified name/value pair. 922 * 923 * @param name The header name. 924 * @param value The header value. 925 * @return A new header. 926 */ 927 private Header createPart(String name, Object value) { 928 boolean isResolving = varResolver != null; 929 930 if (value instanceof Supplier<?>) { 931 Supplier<?> value2 = (Supplier<?>)value; 932 return isResolving ? new BasicHeader(name, resolver(value2)) : new BasicHeader(name, value2); 933 } 934 return isResolving ? new BasicHeader(name, resolver(value)) : new BasicHeader(name, value); 935 } 936 937 private Supplier<Object> resolver(Object input) { 938 return ()->varResolver.resolve(stringify(unwrap(input))); 939 } 940 941 private Object unwrap(Object o) { 942 while (o instanceof Supplier) 943 o = ((Supplier<?>)o).get(); 944 return o; 945 } 946 947 private boolean eq(String s1, String s2) { 948 return caseSensitive ? StringUtils.eq(s1, s2) : StringUtils.eqic(s1, s2); 949 } 950 951 @Override /* Object */ 952 public String toString() { 953 return "[" + join(this, ", ") + "]"; 954 } 955 956 // <FluentSetters> 957 958 @Override /* GENERATED - org.apache.juneau.collections.ControlledArrayList */ 959 public HeaderList setUnmodifiable() { 960 super.setUnmodifiable(); 961 return this; 962 } 963 964 // </FluentSetters> 965}