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