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}