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}