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 RuntimeException("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(x -> set(x)); 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 (int i = 0; i < values.length; i++) 339 if (values[i] != null) 340 append(values[i]); 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(x -> append(x)); 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 (int i = 0; i < values.length; i++) 449 remove(values[i]); 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(x -> remove(x)); 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 (int i = 0; i < names.length; i++) 488 remove(names[i]); 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 (int i1 = 0, j1 = values.size(); i1 < j1; i1++) { 587 Header h = values.get(i1); 588 if (h != null) { 589 for (int i2 = 0, j2 = size(); i2 < j2; i2++) { 590 Header x = get(i2); 591 if (eq(x.getName(), h.getName())) { 592 remove(i2); 593 j2--; 594 } 595 } 596 } 597 } 598 599 for (int i = 0, j = values.size(); i < j; i++) { 600 Header x = values.get(i); 601 if (x != null) { 602 add(x); 603 } 604 } 605 } 606 607 return this; 608 } 609 610 /** 611 * Gets the first header with the given name. 612 * 613 * <p> 614 * Header name comparison is case insensitive. 615 * 616 * @param name The header name. 617 * @return The first matching header, or {@link Optional#empty()} if not found. 618 */ 619 public Optional<Header> getFirst(String name) { 620 for (int i = 0; i < size(); i++) { 621 Header x = get(i); 622 if (eq(x.getName(), name)) 623 return optional(x); 624 } 625 return empty(); 626 } 627 628 /** 629 * Gets the last header with the given name. 630 * 631 * <p> 632 * Header name comparison is case insensitive. 633 * 634 * @param name The header name. 635 * @return The last matching header, or {@link Optional#empty()} if not found. 636 */ 637 public Optional<Header> getLast(String name) { 638 for (int i = size() - 1; i >= 0; i--) { 639 Header x = get(i); 640 if (eq(x.getName(), name)) 641 return optional(x); 642 } 643 return empty(); 644 } 645 646 /** 647 * Gets a header representing all of the header values with the given name. 648 * 649 * <p> 650 * If more that one header with the given name exists the values will be combined with <js>", "</js> as per 651 * <a href='https://tools.ietf.org/html/rfc2616#section-4.2'>RFC 2616 Section 4.2</a>. 652 * 653 * @param name The header name. 654 * @return A header with a condensed value, or {@link Optional#empty()} if no headers by the given name are present 655 */ 656 public Optional<Header> get(String name) { 657 658 Header first = null; 659 List<Header> rest = null; 660 for (Header x : this) { 661 if (eq(x.getName(), name)) { 662 if (first == null) 663 first = x; 664 else { 665 if (rest == null) 666 rest = list(); 667 rest.add(x); 668 } 669 } 670 } 671 672 if (first == null) 673 return empty(); 674 675 if (rest == null) 676 return optional(first); 677 678 CharArrayBuffer sb = new CharArrayBuffer(128); 679 sb.append(first.getValue()); 680 for (int i = 0; i < rest.size(); i++) { 681 sb.append(", "); 682 sb.append(rest.get(i).getValue()); 683 } 684 685 return optional(new BasicHeader(name, sb.toString())); 686 } 687 688 /** 689 * Gets a header representing all of the header values with the given name. 690 * 691 * <p> 692 * If more that one header with the given name exists the values will be combined with <js>", "</js> as per 693 * <a href='https://tools.ietf.org/html/rfc2616#section-4.2'>RFC 2616 Section 4.2</a>. 694 * 695 * <p> 696 * The implementation class must have a public constructor taking in one of the following argument lists: 697 * <ul> 698 * <li><c>X(String <jv>value</jv>)</c> 699 * <li><c>X(Object <jv>value</jv>)</c> 700 * <li><c>X(String <jv>name</jv>, String <jv>value</jv>)</c> 701 * <li><c>X(String <jv>name</jv>, Object <jv>value</jv>)</c> 702 * </ul> 703 * 704 * <h5 class='figure'>Example</h5> 705 * <p class='bjava'> 706 * BasicIntegerHeader <jv>age</jv> = headerList.get(<js>"Age"</js>, BasicIntegerHeader.<jk>class</jk>); 707 * </p> 708 * 709 * @param <T> The header implementation class. 710 * @param name The header name. 711 * @param type The header implementation class. 712 * @return A header with a condensed value or <jk>null</jk> if no headers by the given name are present 713 */ 714 public <T> Optional<T> get(String name, Class<T> type) { 715 716 Header first = null; 717 List<Header> rest = null; 718 for (Header x : this) { 719 if (eq(x.getName(), name)) { 720 if (first == null) 721 first = x; 722 else { 723 if (rest == null) 724 rest = list(); 725 rest.add(x); 726 } 727 } 728 } 729 730 if (first == null) 731 return empty(); 732 733 if (rest == null) 734 return optional(HeaderBeanMeta.of(type).construct(name, first.getValue())); 735 736 CharArrayBuffer sb = new CharArrayBuffer(128); 737 sb.append(first.getValue()); 738 for (int i = 0; i < rest.size(); i++) { 739 sb.append(", "); 740 sb.append(rest.get(i).getValue()); 741 } 742 743 return optional(HeaderBeanMeta.of(type).construct(name, sb.toString())); 744 } 745 746 /** 747 * Gets a header representing all of the header values with the given name. 748 * 749 * <p> 750 * Same as {@link #get(String, Class)} but the header name is pulled from the {@link org.apache.juneau.http.annotation.Header#name()} or 751 * {@link org.apache.juneau.http.annotation.Header#value()} annotations. 752 * 753 * <h5 class='figure'>Example</h5> 754 * <p class='bjava'> 755 * Age <jv>age</jv> = headerList.get(Age.<jk>class</jk>); 756 * </p> 757 * 758 * @param <T> The return type. 759 * @param type The header implementation class. 760 * @return A header with a condensed value or <jk>null</jk> if no headers by the given name are present 761 */ 762 public <T> Optional<T> get(Class<T> type) { 763 assertArgNotNull("type", type); 764 765 String name = HeaderBeanMeta.of(type).getSchema().getName(); 766 assertArg(name != null, "Header name could not be found on bean type ''{0}''", type.getName()); 767 768 return get(name, type); 769 } 770 771 /** 772 * Gets all of the headers. 773 * 774 * <p> 775 * The returned array maintains the relative order in which the headers were added. 776 * Each call creates a new array not backed by this list. 777 * 778 * <p> 779 * As a general rule, it's more efficient to use the other methods with consumers to 780 * get headers. 781 * 782 * @return An array containing all headers, never <jk>null</jk>. 783 */ 784 public Header[] getAll() { 785 return stream().toArray(Header[]::new); 786 } 787 788 /** 789 * Gets all of the headers with the given name. 790 * 791 * <p> 792 * The returned array maintains the relative order in which the headers were added. 793 * Header name comparison is case insensitive. 794 * Headers with null values are ignored. 795 * Each call creates a new array not backed by this list. 796 * 797 * <p> 798 * As a general rule, it's more efficient to use the other methods with consumers to 799 * get headers. 800 * 801 * @param name The header name. 802 * 803 * @return An array containing all matching headers, never <jk>null</jk>. 804 */ 805 public Header[] getAll(String name) { 806 return stream().filter(x -> eq(x.getName(), name)).toArray(Header[]::new); 807 } 808 809 /** 810 * Performs an action on the values for all matching headers in this list. 811 * 812 * @param filter A predicate to apply to each element to determine if it should be included. Can be <jk>null</jk>. 813 * @param action An action to perform on each element. 814 * @return This object. 815 */ 816 public HeaderList forEachValue(Predicate<Header> filter, Consumer<String> action) { 817 return forEach(filter, x -> action.accept(x.getValue())); 818 } 819 820 /** 821 * Performs an action on the values of all matching headers in this list. 822 * 823 * @param name The header name. 824 * @param action An action to perform on each element. 825 * @return This object. 826 */ 827 public HeaderList forEachValue(String name, Consumer<String> action) { 828 return forEach(name, x -> action.accept(x.getValue())); 829 } 830 831 /** 832 * Returns all the string values for all headers with the specified name. 833 * 834 * @param name The header name. 835 * @return An array containing all values. Never <jk>null</jk>. 836 */ 837 public String[] getValues(String name) { 838 return stream().filter(x -> eq(x.getName(), name)).map(x -> x.getValue()).toArray(String[]::new); 839 } 840 841 /** 842 * Tests if headers with the given name are contained within this list. 843 * 844 * <p> 845 * Header name comparison is case insensitive. 846 * 847 * @param name The header name. 848 * @return <jk>true</jk> if at least one header with the name is present. 849 */ 850 public boolean contains(String name) { 851 return stream().anyMatch(x -> eq(x.getName(), name)); 852 } 853 854 /** 855 * Returns an iterator over this list of headers. 856 * 857 * @return A new iterator over this list of headers. 858 */ 859 public HeaderIterator headerIterator() { 860 return new BasicHeaderIterator(toArray(new Header[0]), null, caseSensitive); 861 } 862 863 /** 864 * Returns an iterator over the headers with a given name in this list. 865 * 866 * @param name The name of the headers over which to iterate, or <jk>null</jk> for all headers 867 * 868 * @return A new iterator over the matching headers in this list. 869 */ 870 public HeaderIterator headerIterator(String name) { 871 return new BasicHeaderIterator(getAll(name), name, caseSensitive); 872 } 873 874 /** 875 * Performs an action on all headers with the specified name in this list. 876 * 877 * <p> 878 * This is the preferred method for iterating over headers as it does not involve 879 * creation or copy of lists/arrays. 880 * 881 * @param name The header name. 882 * @param action An action to perform on each element. 883 * @return This object. 884 */ 885 public HeaderList forEach(String name, Consumer<Header> action) { 886 return forEach(x -> eq(name, x.getName()), action); 887 } 888 889 /** 890 * Performs an action on all matching headers in this list. 891 * 892 * <p> 893 * This is the preferred method for iterating over headers as it does not involve 894 * creation or copy of lists/arrays. 895 * 896 * @param filter A predicate to apply to each element to determine if it should be included. Can be <jk>null</jk>. 897 * @param action An action to perform on each element. 898 * @return This object. 899 */ 900 public HeaderList forEach(Predicate<Header> filter, Consumer<Header> action) { 901 forEach(x -> consume(filter, action, x)); 902 return this; 903 } 904 905 /** 906 * Returns a stream of the headers in this list with the specified name. 907 * 908 * <p> 909 * This does not involve a copy of the underlying array of <c>Header</c> objects so should perform well. 910 * 911 * @param name The header name. 912 * @return This object. 913 */ 914 public Stream<Header> stream(String name) { 915 return stream().filter(x->eq(name, x.getName())); 916 } 917 918 //------------------------------------------------------------------------------------------------------------- 919 // Other methods 920 //------------------------------------------------------------------------------------------------------------- 921 922 /** 923 * Creates a new header out of the specified name/value pair. 924 * 925 * @param name The header name. 926 * @param value The header value. 927 * @return A new header. 928 */ 929 private Header createPart(String name, Object value) { 930 boolean isResolving = varResolver != null; 931 932 if (value instanceof Supplier<?>) { 933 Supplier<?> value2 = (Supplier<?>)value; 934 return isResolving ? new BasicHeader(name, resolver(value2)) : new BasicHeader(name, value2); 935 } 936 return isResolving ? new BasicHeader(name, resolver(value)) : new BasicHeader(name, value); 937 } 938 939 private Supplier<Object> resolver(Object input) { 940 return ()->varResolver.resolve(stringify(unwrap(input))); 941 } 942 943 private Object unwrap(Object o) { 944 while (o instanceof Supplier) 945 o = ((Supplier<?>)o).get(); 946 return o; 947 } 948 949 private boolean eq(String s1, String s2) { 950 return caseSensitive ? StringUtils.eq(s1, s2) : StringUtils.eqic(s1, s2); 951 } 952 953 @Override /* Object */ 954 public String toString() { 955 return "[" + join(this, ", ") + "]"; 956 } 957 958 // <FluentSetters> 959 960 @Override /* GENERATED - org.apache.juneau.collections.ControlledArrayList */ 961 public HeaderList setUnmodifiable() { 962 super.setUnmodifiable(); 963 return this; 964 } 965 966 // </FluentSetters> 967}