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