001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.http.classic;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.net.*;
022import java.time.*;
023import java.util.*;
024import java.util.function.*;
025
026import org.apache.http.*;
027import org.apache.juneau.commons.httppart.*;
028import org.apache.juneau.commons.lang.*;
029import org.apache.juneau.commons.reflect.*;
030import org.apache.juneau.http.classic.header.*;
031import org.apache.juneau.http.classic.part.*;
032import org.apache.juneau.marshall.*;
033
034/**
035 * Standard predefined HTTP parts.
036 *
037 * <h5 class='section'>See Also:</h5><ul>
038 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommon">juneau-rest-common</a>
039 * </ul>
040 */
041@SuppressWarnings({
042   "java:S3740" // Raw Supplier/NameValuePair types used in factory methods where HTTP part value type cannot be statically parameterized
043})
044public class HttpParts {
045
046   /**
047    * Prevents instantiation.
048    */
049   private HttpParts() {}
050
051   private static final Function<ClassMeta<?>,String> HEADER_NAME_FUNCTION = x -> {
052      var n = Holder.<String>empty();
053      x.forEachAnnotation(org.apache.juneau.http.Header.class, y -> ine(y.value()), y -> n.set(y.value()));
054      x.forEachAnnotation(org.apache.juneau.http.Header.class, y -> ine(y.name()), y -> n.set(y.name()));
055      return n.orElse(null);
056   };
057
058   private static final Function<ClassMeta<?>,String> QUERY_NAME_FUNCTION = x -> {
059      var n = Holder.<String>empty();
060      x.forEachAnnotation(org.apache.juneau.http.Query.class, y -> ine(y.value()), y -> n.set(y.value()));
061      x.forEachAnnotation(org.apache.juneau.http.Query.class, y -> ine(y.name()), y -> n.set(y.name()));
062      return n.orElse(null);
063   };
064
065   private static final Function<ClassMeta<?>,String> FORMDATA_NAME_FUNCTION = x -> {
066      var n = Holder.<String>empty();
067      x.forEachAnnotation(org.apache.juneau.http.FormData.class, y -> ine(y.value()), y -> n.set(y.value()));
068      x.forEachAnnotation(org.apache.juneau.http.FormData.class, y -> ine(y.name()), y -> n.set(y.name()));
069      return n.orElse(null);
070   };
071
072   private static final Function<ClassMeta<?>,String> PATH_NAME_FUNCTION = x -> {
073      var n = Holder.<String>empty();
074      x.forEachAnnotation(org.apache.juneau.http.Path.class, y -> ine(y.value()), y -> n.set(y.value()));
075      x.forEachAnnotation(org.apache.juneau.http.Path.class, y -> ine(y.name()), y -> n.set(y.name()));
076      return n.orElse(null);
077   };
078
079   private static final Function<ClassMeta<?>,ConstructorInfo> CONSTRUCTOR_FUNCTION = x -> x.getPublicConstructor(y -> y.hasParameterTypes(String.class)).orElseGet(() -> x.getPublicConstructor(y -> y.hasParameterTypes(String.class, String.class)).orElse(null));
080
081   /**
082    * Creates a {@link BasicPart} from a name/value pair string (e.g. <js>"Foo: bar"</js>)
083    *
084    * @param pair The pair string.
085    * @return A new {@link BasicPart} object.
086    */
087   public static final BasicPart basicPart(String pair) {
088      return BasicPart.ofPair(pair);
089   }
090
091   /**
092    * Creates a new {@link BasicPart} part.
093    *
094    * @param name The part name.
095    * @param value The part value.
096    * @return A new {@link BasicPart} object.
097    */
098   public static final BasicPart basicPart(String name, Object value) {
099      return BasicPart.of(name, value);
100   }
101
102   /**
103    * Creates a new {@link BasicPart} part with a delayed value.
104    *
105    * <p>
106    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
107    *
108    * @param name The part name.
109    * @param value The part value supplier.
110    * @return A new {@link BasicPart} object.
111    */
112   public static final BasicPart basicPart(String name, Supplier<?> value) {
113      return BasicPart.of(name, value);
114   }
115
116   /**
117    * Creates a new {@link BasicBooleanPart} part.
118    *
119    * @param name The part name.
120    * @param value
121    *    The part value.
122    *    <br>Can be any of the following:
123    *    <ul>
124    *       <li>{@link Boolean} - As-is.
125    *       <li>{@link String} - Parsed using {@link Boolean#parseBoolean(String)}.
126    *       <li>Anything else - Converted to <c>String</c> and then parsed.
127    *    </ul>
128    * @return A new {@link BasicBooleanPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
129    */
130   public static final BasicBooleanPart booleanPart(String name, Boolean value) {
131      return BasicBooleanPart.of(name, value);
132   }
133
134   /**
135    * Creates a new {@link BasicBooleanPart} part with a delayed value.
136    *
137    * <p>
138    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
139    *
140    * @param name The part name.
141    * @param value
142    *    The part value supplier.
143    *    <br>Can be any of the following:
144    *    <ul>
145    *       <li>{@link Boolean} - As-is.
146    *       <li>{@link String} - Parsed using {@link Boolean#parseBoolean(String)}.
147    *       <li>Anything else - Converted to <c>String</c> and then parsed.
148    *    </ul>
149    * @return A new {@link BasicBooleanPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
150    */
151   public static final BasicBooleanPart booleanPart(String name, Supplier<Boolean> value) {
152      return BasicBooleanPart.of(name, value);
153   }
154
155   /**
156    * Returns <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object.
157    *
158    * @param o The object to check.
159    * @return <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object.
160    */
161   public static boolean canCast(Object o) {
162      if (o == null)
163         return false;
164      var ci = ClassInfo.of(o);
165      return nn(ci) && ci.isAssignableToAny(Headerable.class, NameValuePair.class, NameValuePairable.class, Map.Entry.class);
166   }
167
168   /**
169    * Utility method for converting an arbitrary object to a {@link NameValuePair}.
170    *
171    * @param o
172    *    The object to cast or convert to a {@link NameValuePair}.
173    * @return Either the same object cast as a {@link NameValuePair} or converted to a {@link NameValuePair}.
174    */
175   public static NameValuePair cast(Object o) {
176      if (o instanceof NameValuePair o2)
177         return o2;
178      if (o instanceof Headerable o2) {
179         Header x = o2.asHeader();
180         return BasicPart.of(x.getName(), x.getValue());
181      }
182      if (o instanceof Map.Entry o4) {
183         return BasicPart.of(s(o4.getKey()), o4.getValue());
184      }
185      throw rex("Object of type %s could not be converted to a Part.", cn(o));
186   }
187
188   /**
189    * Creates a new {@link BasicCsvArrayPart} part.
190    *
191    * @param name The part name.
192    * @param value
193    *    The part value.
194    *    <br>Can be any of the following:
195    *    <ul>
196    *       <li><c>String</c> - A comma-delimited string.
197    *       <li><c>String[]</c> - A pre-parsed value.
198    *       <li>Any other array type - Converted to <c>String[]</c>.
199    *       <li>Any {@link Collection} - Converted to <c>String[]</c>.
200    *       <li>Anything else - Converted to <c>String</c>.
201    *    </ul>
202    * @return A new {@link BasicCsvArrayPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
203    */
204   public static final BasicCsvArrayPart csvArrayPart(String name, String...value) {
205      return BasicCsvArrayPart.of(name, value);
206   }
207
208   /**
209    * Creates a new {@link BasicCsvArrayPart} part with a delayed value.
210    *
211    * <p>
212    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
213    *
214    * @param name The part name.
215    * @param value
216    *    The part value supplier.
217    *    <br>Can be any of the following:
218    *    <ul>
219    *       <li><c>String</c> - A comma-delimited string.
220    *       <li><c>String[]</c> - A pre-parsed value.
221    *       <li>Any other array type - Converted to <c>String[]</c>.
222    *       <li>Any {@link Collection} - Converted to <c>String[]</c>.
223    *       <li>Anything else - Converted to <c>String</c>.
224    *    </ul>
225    * @return A new {@link BasicCsvArrayPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
226    */
227   public static final BasicCsvArrayPart csvArrayPart(String name, Supplier<String[]> value) {
228      return BasicCsvArrayPart.of(name, value);
229   }
230
231   /**
232    * Creates a new {@link BasicDatePart} part with a delayed value.
233    *
234    * <p>
235    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
236    *
237    * @param name The part name.
238    * @param value
239    *    The part value supplier.
240    *    <br>Can be any of the following:
241    *    <ul>
242    *       <li><c>String</c> - An ISO-8601 formated string (e.g. <js>"1994-10-29T19:43:31Z"</js>).
243    *       <li>{@link ZonedDateTime}
244    *       <li>{@link Calendar}
245    *       <li>Anything else - Converted to <c>String</c>.
246    *    </ul>
247    * @return A new {@link BasicDatePart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
248    */
249   public static final BasicDatePart datePart(String name, Supplier<ZonedDateTime> value) {
250      return BasicDatePart.of(name, value);
251   }
252
253   /**
254    * Creates a new {@link BasicDatePart} part.
255    *
256    * @param name The part name.
257    * @param value
258    *    The part value.
259    *    <br>Can be any of the following:
260    *    <ul>
261    *       <li><c>String</c> - An ISO-8601 formated string (e.g. <js>"1994-10-29T19:43:31Z"</js>).
262    *       <li>{@link ZonedDateTime}
263    *       <li>{@link Calendar}
264    *       <li>Anything else - Converted to <c>String</c>.
265    *    </ul>
266    * @return A new {@link BasicDatePart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
267    */
268   public static final BasicDatePart datePart(String name, ZonedDateTime value) {
269      return BasicDatePart.of(name, value);
270   }
271
272   /**
273    * Returns the constructor for the specified type.
274    *
275    * <p>
276    * Looks for one of the following constructors:
277    * <ul class='javatree'>
278    *    <li class='jm><c><jk>public</jk> T(String <jv>value</jv>);</c>
279    *    <li class='jm><c><jk>public</jk> T(String <jv>name</jv>, String <jv>value</jv>);</c>
280    * </ul>
281    *
282    * @param type The header type to find the constructor on.
283    * @return The constructor.  Never <jk>null</jk>.
284    */
285   public static Optional<ConstructorInfo> getConstructor(ClassMeta<?> type) {
286      return type.getProperty("HttpPart.Constructor", CONSTRUCTOR_FUNCTION);
287   }
288
289   /**
290    * Returns the name of the specified part type.
291    *
292    * <p>
293    * Gets the name from one of the following annotations:
294    * <ul class='javatreec'>
295    *    <li class='ja'>{@link org.apache.juneau.http.Header}
296    *    <li class='ja'>{@link org.apache.juneau.http.Query}
297    *    <li class='ja'>{@link org.apache.juneau.http.FormData}
298    *    <li class='ja'>{@link org.apache.juneau.http.Path}
299    * </ul>
300    *
301    * @param partType The part type.
302    * @param type The type to check.
303    * @return The part name.  Never <jk>null</jk>.
304    */
305   public static Optional<String> getName(HttpPartType partType, ClassMeta<?> type) {
306      return switch (partType) {
307         case FORMDATA -> type.getProperty("HttpPart.formData.name", FORMDATA_NAME_FUNCTION);
308         case HEADER -> type.getProperty("HttpPart.header.name", HEADER_NAME_FUNCTION);
309         case PATH -> type.getProperty("HttpPart.path.name", PATH_NAME_FUNCTION);
310         case QUERY -> type.getProperty("HttpPart.query.name", QUERY_NAME_FUNCTION);
311         default -> oe();
312      };
313   }
314
315   /**
316    * Creates a new {@link BasicIntegerPart} part.
317    *
318    * @param name The part name.
319    * @param value
320    *    The part value.
321    *    <br>Can be any of the following:
322    *    <ul>
323    *       <li>{@link Number} - Converted to an integer using {@link Number#intValue()}.
324    *       <li>{@link String} - Parsed using {@link Integer#parseInt(String)}.
325    *       <li>Anything else - Converted to <c>String</c>.
326    *    </ul>
327    * @return A new {@link BasicIntegerPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
328    */
329   public static final BasicIntegerPart integerPart(String name, Integer value) {
330      return BasicIntegerPart.of(name, value);
331   }
332
333   /**
334    * Creates a new {@link BasicIntegerPart} part with a delayed value.
335    *
336    * <p>
337    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
338    *
339    * @param name The part name.
340    * @param value
341    *    The part value supplier.
342    *    <br>Can be any of the following:
343    *    <ul>
344    *       <li>{@link Number} - Converted to an integer using {@link Number#intValue()}.
345    *       <li>{@link String} - Parsed using {@link Integer#parseInt(String)}.
346    *       <li>Anything else - Converted to <c>String</c>.
347    *    </ul>
348    * @return A new {@link BasicIntegerPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
349    */
350   public static final BasicIntegerPart integerPart(String name, Supplier<Integer> value) {
351      return BasicIntegerPart.of(name, value);
352   }
353
354   /**
355    * Returns <jk>true</jk> if the specified type is a part type.
356    *
357    * <p>
358    * A part type extends from either {@link org.apache.http.Header} or {@link org.apache.http.NameValuePair}
359    * or is annotated with {@link org.apache.juneau.http.Header}, {@link org.apache.juneau.http.Query},
360    * {@link org.apache.juneau.http.FormData}, or {@link org.apache.juneau.http.Path}.
361    *
362    * @param partType The part type.
363    * @param type The type to check.
364    * @return <jk>true</jk> if the specified type is a part type.
365    */
366   public static boolean isHttpPart(HttpPartType partType, ClassMeta<?> type) {
367      return switch (partType) {
368         case PATH, QUERY, FORMDATA -> type.getProperty("HttpPart.isNameValuePair", x -> x.isAssignableTo(NameValuePair.class)).orElse(false);
369         case HEADER -> type.getProperty("HttpPart.isHeader", x -> x.isAssignableTo(org.apache.http.Header.class)).orElse(false);
370         default -> false;
371      };
372   }
373
374   /**
375    * Creates a new {@link BasicLongPart} part.
376    *
377    * @param name The part name.
378    * @param value
379    *    The part value.
380    *    <br>Can be any of the following:
381    *    <ul>
382    *       <li>{@link Number} - Converted to a long using {@link Number#longValue()}.
383    *       <li>{@link String} - Parsed using {@link Long#parseLong(String)}.
384    *       <li>Anything else - Converted to <c>String</c>.
385    *    </ul>
386    * @return A new {@link BasicLongPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
387    */
388   public static final BasicLongPart longPart(String name, Long value) {
389      return BasicLongPart.of(name, value);
390   }
391
392   /**
393    * Creates a new {@link BasicLongPart} part with a delayed value.
394    *
395    * <p>
396    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
397    *
398    * @param name The part name.
399    * @param value
400    *    The part value supplier.
401    *    <br>Can be any of the following:
402    *    <ul>
403    *       <li>{@link Number} - Converted to a long using {@link Number#longValue()}.
404    *       <li>{@link String} - Parsed using {@link Long#parseLong(String)}.
405    *       <li>Anything else - Converted to <c>String</c>.
406    *    </ul>
407    * @return A new {@link BasicLongPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
408    */
409   public static final BasicLongPart longPart(String name, Supplier<Long> value) {
410      return BasicLongPart.of(name, value);
411   }
412
413   /**
414    * Instantiates a new {@link PartList}.
415    *
416    * @return A new part list.
417    */
418   public static final PartList partList() {
419      return PartList.create();
420   }
421
422   /**
423    * Creates a new {@link PartList} initialized with the specified parts.
424    *
425    * @param parts The parts to add to the list.  Can be <jk>null</jk>.  <jk>null</jk> entries are ignored.
426    * @return A new unmodifiable instance, never <jk>null</jk>.
427    */
428   public static final PartList partList(List<NameValuePair> parts) {
429      return PartList.of(parts);
430   }
431
432   /**
433    * Creates a new {@link PartList} initialized with the specified parts.
434    *
435    * @param parts The parts to add to the list.  <jk>null</jk> entries are ignored.
436    * @return A new unmodifiable instance, never <jk>null</jk>.
437    */
438   public static final PartList partList(NameValuePair...parts) {
439      return PartList.of(parts);
440   }
441
442   /**
443    * Creates a new {@link PartList} initialized with the specified name/value pairs.
444    *
445    * @param pairs
446    *    Initial list of pairs.
447    *    <br>Must be an even number of parameters representing key/value pairs.
448    * @throws RuntimeException If odd number of parameters were specified.
449    * @return A new instance.
450    */
451   public static PartList partList(String...pairs) {
452      return PartList.ofPairs(pairs);
453   }
454
455   /**
456    * Creates a new {@link SerializedPart} part.
457    *
458    * @param name The part name.
459    * @param value
460    *    The part value.
461    *    <br>Can be any POJO.
462    * @return A new {@link SerializedPart} object, never <jk>null</jk>.
463    */
464   public static final SerializedPart serializedPart(String name, Object value) {
465      return SerializedPart.of(name, value);
466   }
467
468   /**
469    * Creates a new {@link SerializedPart} part with a delayed value.
470    *
471    * @param name The part name.
472    * @param value
473    *    The part value supplier.
474    *    <br>Can be a supplier of any POJO.
475    * @return A new {@link SerializedPart} object, never <jk>null</jk>.
476    */
477   public static final SerializedPart serializedPart(String name, Supplier<?> value) {
478      return SerializedPart.of(name, value);
479   }
480
481   /**
482    * Creates a new {@link BasicStringPart} part.
483    *
484    * @param name The part name.
485    * @param value
486    *    The part value.
487    *    <br>Can be any of the following:
488    *    <ul>
489    *       <li>{@link String}
490    *       <li>Anything else - Converted to <c>String</c> then parsed.
491    *    </ul>
492    * @return A new {@link BasicStringPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
493    */
494   public static final BasicStringPart stringPart(String name, String value) {
495      return BasicStringPart.of(name, value);
496   }
497
498   /**
499    * Creates a new {@link BasicStringPart} part with a delayed value.
500    *
501    * <p>
502    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
503    *
504    * @param name The part name.
505    * @param value
506    *    The part value supplier.
507    *    <br>Can be any of the following:
508    *    <ul>
509    *       <li>{@link String}
510    *       <li>Anything else - Converted to <c>String</c> then parsed.
511    *    </ul>
512    * @return A new {@link BasicStringPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
513    */
514   public static final BasicStringPart stringPart(String name, Supplier<String> value) {
515      return BasicStringPart.of(name, value);
516   }
517
518   /**
519    * Creates a new {@link BasicUriPart} part with a delayed value.
520    *
521    * <p>
522    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
523    *
524    * @param name The header name.
525    * @param value
526    *    The header value supplier.
527    *    <br>Can be any of the following:
528    *    <ul>
529    *       <li>{@link String}
530    *       <li>Anything else - Converted to <c>String</c> then parsed.
531    *    </ul>
532    * @return A new {@link BasicUriPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
533    */
534   public static final BasicUriPart uriPart(String name, Supplier<URI> value) {
535      return BasicUriPart.of(name, value);
536   }
537
538   /**
539    * Creates a new {@link BasicUriPart} part.
540    *
541    * @param name The header name.
542    * @param value
543    *    The header value.
544    *    <br>Can be any of the following:
545    *    <ul>
546    *       <li>{@link String}
547    *       <li>Anything else - Converted to <c>String</c> then parsed.
548    *    </ul>
549    * @return A new {@link BasicUriPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
550    */
551   public static final BasicUriPart uriPart(String name, URI value) {
552      return BasicUriPart.of(name, value);
553   }
554}