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