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>, ()-&gt;<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&lt;?&gt;)}
232    *    <li class='jm'>{@link #prepend(String, Object) prepend(String,Object)}
233    *    <li class='jm'>{@link #prepend(String, Supplier) prepend(String,Supplier&lt;?&gt;)}
234    *    <li class='jm'>{@link #set(String, Object) set(String,Object)}
235    *    <li class='jm'>{@link #set(String, Supplier) set(String,Supplier&lt;?&gt;)}
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&lt;?&gt;)}
255    *    <li class='jm'>{@link #prepend(String, Object) prepend(String,Object)}
256    *    <li class='jm'>{@link #prepend(String, Supplier) prepend(String,Supplier&lt;?&gt;)}
257    *    <li class='jm'>{@link #set(String, Object) set(String,Object)}
258    *    <li class='jm'>{@link #set(String, Supplier) set(String,Supplier&lt;?&gt;)}
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}