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