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.dto.swagger; 014 015import static org.apache.juneau.common.internal.StringUtils.*; 016import static org.apache.juneau.internal.CollectionUtils.*; 017import static org.apache.juneau.internal.ConverterUtils.*; 018 019import java.util.*; 020 021import org.apache.juneau.*; 022import org.apache.juneau.annotation.*; 023import org.apache.juneau.internal.*; 024import org.apache.juneau.marshaller.*; 025 026/** 027 * Describes a single HTTP header. 028 * 029 * <h5 class='section'>Example:</h5> 030 * <p class='bjava'> 031 * <jc>// Construct using SwaggerBuilder.</jc> 032 * HeaderInfo <jv>headerInfo</jv> = <jsm>headerInfo</jsm>(<js>"integer"</js>).description(<js>"The number of allowed requests in the current period"</js>); 033 * 034 * <jc>// Serialize using JsonSerializer.</jc> 035 * String <jv>json</jv> = JsonSerializer.<jsf>DEFAULT</jsf>.toString(<jv>headerInfo</jv>); 036 * 037 * <jc>// Or just use toString() which does the same as above.</jc> 038 * <jv>json</jv> = <jv>headerInfo</jv>.toString(); 039 * </p> 040 * <p class='bjson'> 041 * <jc>// Output</jc> 042 * { 043 * <js>"description"</js>: <js>"The number of allowed requests in the current period"</js>, 044 * <js>"type"</js>: <js>"integer"</js> 045 * } 046 * </p> 047 * 048 * <h5 class='section'>See Also:</h5><ul> 049 * <li class='link'><a class="doclink" href="../../../../../index.html#jrs.Swagger">Overview > juneau-rest-server > Swagger</a> 050 * </ul> 051 */ 052@Bean(properties="description,type,format,items,collectionFormat,default,maximum,exclusiveMaximum,minimum,exclusiveMinimum,maxLength,minLength,pattern,maxItems,minItems,uniqueItems,enum,multipleOf,$ref,example,*") 053@SuppressWarnings({"unchecked"}) 054@FluentSetters 055public class HeaderInfo extends SwaggerElement { 056 057 private static final String[] VALID_TYPES = {"string", "number", "integer", "boolean", "array"}; 058 private static final String[] VALID_COLLECTION_FORMATS = {"csv","ssv","tsv","pipes","multi"}; 059 060 private String 061 description, 062 type, 063 format, 064 collectionFormat, 065 pattern, 066 ref; 067 private Number 068 maximum, 069 minimum, 070 multipleOf; 071 private Integer 072 maxLength, 073 minLength, 074 maxItems, 075 minItems; 076 private Boolean 077 exclusiveMaximum, 078 exclusiveMinimum, 079 uniqueItems; 080 private Items items; 081 private Object _default; 082 private Set<Object> _enum; 083 private Object example; 084 085 /** 086 * Default constructor. 087 */ 088 public HeaderInfo() {} 089 090 /** 091 * Copy constructor. 092 * 093 * @param copyFrom The object to copy. 094 */ 095 public HeaderInfo(HeaderInfo copyFrom) { 096 super(copyFrom); 097 098 this.collectionFormat = copyFrom.collectionFormat; 099 this._default = copyFrom._default; 100 this.description = copyFrom.description; 101 this._enum = copyOf(copyFrom._enum); 102 this.example = copyFrom.example; 103 this.exclusiveMaximum = copyFrom.exclusiveMaximum; 104 this.exclusiveMinimum = copyFrom.exclusiveMinimum; 105 this.format = copyFrom.format; 106 this.items = copyFrom.items == null ? null : copyFrom.items.copy(); 107 this.maximum = copyFrom.maximum; 108 this.maxItems = copyFrom.maxItems; 109 this.maxLength = copyFrom.maxLength; 110 this.minimum = copyFrom.minimum; 111 this.minItems = copyFrom.minItems; 112 this.minLength = copyFrom.minLength; 113 this.multipleOf = copyFrom.multipleOf; 114 this.pattern = copyFrom.pattern; 115 this.type = copyFrom.type; 116 this.uniqueItems = copyFrom.uniqueItems; 117 } 118 119 /** 120 * Make a deep copy of this object. 121 * 122 * @return A deep copy of this object. 123 */ 124 public HeaderInfo copy() { 125 return new HeaderInfo(this); 126 } 127 128 @Override /* SwaggerElement */ 129 protected HeaderInfo strict() { 130 super.strict(); 131 return this; 132 } 133 134 135 //----------------------------------------------------------------------------------------------------------------- 136 // Properties 137 //----------------------------------------------------------------------------------------------------------------- 138 139 /** 140 * Bean property getter: <property>collectionFormat</property>. 141 * 142 * <p> 143 * Determines the format of the array if type array is used. 144 * 145 * @return The property value, or <jk>null</jk> if it is not set. 146 */ 147 public String getCollectionFormat() { 148 return collectionFormat; 149 } 150 151 /** 152 * Bean property setter: <property>collectionFormat</property>. 153 * 154 * <p> 155 * Determines the format of the array if type array is used. 156 * 157 * @param value 158 * The new value for this property. 159 * <br>Valid values: 160 * <ul> 161 * <li><js>"csv"</js> (default) - comma separated values <c>foo,bar</c>. 162 * <li><js>"ssv"</js> - space separated values <c>foo bar</c>. 163 * <li><js>"tsv"</js> - tab separated values <c>foo\tbar</c>. 164 * <li><js>"pipes"</js> - pipe separated values <c>foo|bar</c>. 165 * </ul> 166 * <br>Can be <jk>null</jk> to unset the property. 167 * @return This object. 168 */ 169 public HeaderInfo setCollectionFormat(String value) { 170 if (isStrict() && ! ArrayUtils.contains(value, VALID_COLLECTION_FORMATS)) 171 throw new BasicRuntimeException( 172 "Invalid value passed in to setCollectionFormat(String). Value=''{0}'', valid values={1}", 173 value, Json5.of(VALID_COLLECTION_FORMATS) 174 ); 175 collectionFormat = value; 176 return this; 177 } 178 179 /** 180 * Bean property getter: <property>default</property>. 181 * 182 * <p> 183 * Declares the value of the header that the server will use if none is provided. 184 * 185 * <h5 class='section'>Notes:</h5><ul> 186 * <li class='note'> 187 * <js>"default"</js> has no meaning for required items. 188 * <li class='note'> 189 * Unlike JSON Schema this value MUST conform to the defined <c>type</c> for the header. 190 * </ul> 191 * 192 * @return The property value, or <jk>null</jk> if it is not set. 193 */ 194 public Object getDefault() { 195 return _default; 196 } 197 198 /** 199 * Bean property setter: <property>default</property>. 200 * 201 * <p> 202 * Declares the value of the header that the server will use if none is provided. 203 * 204 * <h5 class='section'>Notes:</h5><ul> 205 * <li class='note'> 206 * <js>"default"</js> has no meaning for required items. 207 * <li class='note'> 208 * Unlike JSON Schema this value MUST conform to the defined <c>type</c> for the header. 209 * </ul> 210 * 211 * @param value 212 * The new value for this property. 213 * <br>Can be <jk>null</jk> to unset the property. 214 * @return This object. 215 */ 216 public HeaderInfo setDefault(Object value) { 217 _default = value; 218 return this; 219 } 220 221 /** 222 * Bean property getter: <property>description</property>. 223 * 224 * <p> 225 * A short description of the header. 226 * 227 * @return The property value, or <jk>null</jk> if it is not set. 228 */ 229 public String getDescription() { 230 return description; 231 } 232 233 /** 234 * Bean property setter: <property>description</property>. 235 * 236 * <p> 237 * A short description of the header. 238 * 239 * @param value 240 * The new value for this property. 241 * <br>Can be <jk>null</jk> to unset the property. 242 * @return This object. 243 */ 244 public HeaderInfo setDescription(String value) { 245 description = value; 246 return this; 247 } 248 249 /** 250 * Bean property getter: <property>enum</property>. 251 * 252 * @return The property value, or <jk>null</jk> if it is not set. 253 */ 254 public Set<Object> getEnum() { 255 return _enum; 256 } 257 258 /** 259 * Bean property setter: <property>enum</property>. 260 * 261 * @param value 262 * The new value for this property. 263 * <br>Can be <jk>null</jk> to unset the property. 264 * @return This object. 265 */ 266 public HeaderInfo setEnum(Collection<Object> value) { 267 _enum = setFrom(value); 268 return this; 269 } 270 271 /** 272 * Bean property setter: <property>enum</property>. 273 * 274 * @param value 275 * The new value for this property. 276 * @return This object. 277 */ 278 public HeaderInfo setEnum(Object...value) { 279 return setEnum(Arrays.asList(value)); 280 } 281 282 /** 283 * Bean property fluent setter: <property>enum</property>. 284 * 285 * @param value 286 * The new value for this property. 287 * <br>Strings can be JSON arrays. 288 * @return This object. 289 */ 290 public HeaderInfo addEnum(Object...value) { 291 setEnum(setBuilder(_enum).sparse().add(value).build()); 292 return this; 293 } 294 295 /** 296 * Bean property getter: <property>example</property>. 297 * 298 * @return The property value, or <jk>null</jk> if it is not set. 299 */ 300 public Object getExample() { 301 return example; 302 } 303 304 /** 305 * Bean property setter: <property>example</property>. 306 * 307 * @param value 308 * The new value for this property. 309 * <br>Can be <jk>null</jk> to unset the property. 310 * @return This object. 311 */ 312 public HeaderInfo setExample(Object value) { 313 example = value; 314 return this; 315 } 316 317 /** 318 * Bean property getter: <property>exclusiveMaximum</property>. 319 * 320 * @return The property value, or <jk>null</jk> if it is not set. 321 */ 322 public Boolean getExclusiveMaximum() { 323 return exclusiveMaximum; 324 } 325 326 /** 327 * Bean property setter: <property>exclusiveMaximum</property>. 328 * 329 * @param value 330 * The new value for this property. 331 * <br>Can be <jk>null</jk> to unset the property. 332 * @return This object. 333 */ 334 public HeaderInfo setExclusiveMaximum(Boolean value) { 335 exclusiveMaximum = value; 336 return this; 337 } 338 339 /** 340 * Bean property getter: <property>exclusiveMinimum</property>. 341 * 342 * @return The property value, or <jk>null</jk> if it is not set. 343 */ 344 public Boolean getExclusiveMinimum() { 345 return exclusiveMinimum; 346 } 347 348 /** 349 * Bean property setter: <property>exclusiveMinimum</property>. 350 * 351 * @param value 352 * The new value for this property. 353 * <br>Can be <jk>null</jk> to unset the property. 354 * @return This object. 355 */ 356 public HeaderInfo setExclusiveMinimum(Boolean value) { 357 exclusiveMinimum = value; 358 return this; 359 } 360 361 /** 362 * Bean property getter: <property>format</property>. 363 * 364 * <p> 365 * The extending format for the previously mentioned <c>type</c>. 366 * 367 * @return The property value, or <jk>null</jk> if it is not set. 368 */ 369 public String getFormat() { 370 return format; 371 } 372 373 /** 374 * Bean property setter: <property>format</property>. 375 * 376 * <p> 377 * The extending format for the previously mentioned <c>type</c>. 378 * 379 * @param value 380 * The new value for this property. 381 * <br>Can be <jk>null</jk> to unset the property. 382 * @return This object. 383 */ 384 public HeaderInfo setFormat(String value) { 385 format = value; 386 return this; 387 } 388 389 /** 390 * Bean property getter: <property>items</property>. 391 * 392 * <p> 393 * Describes the type of items in the array. 394 * 395 * @return The property value, or <jk>null</jk> if it is not set. 396 */ 397 public Items getItems() { 398 return items; 399 } 400 401 /** 402 * Bean property setter: <property>items</property>. 403 * 404 * <p> 405 * Describes the type of items in the array. 406 * 407 * @param value 408 * The new value for this property. 409 * <br>Property value is required if <c>type</c> is <js>"array"</js>. 410 * <br>Can be <jk>null</jk> to unset the property. 411 * @return This object. 412 */ 413 public HeaderInfo setItems(Items value) { 414 items = value; 415 return this; 416 } 417 418 /** 419 * Bean property getter: <property>maximum</property>. 420 * 421 * @return The property value, or <jk>null</jk> if it is not set. 422 */ 423 public Number getMaximum() { 424 return maximum; 425 } 426 427 /** 428 * Bean property setter: <property>maximum</property>. 429 * 430 * @param value 431 * The new value for this property. 432 * <br>Can be <jk>null</jk> to unset the property. 433 * @return This object. 434 */ 435 public HeaderInfo setMaximum(Number value) { 436 maximum = value; 437 return this; 438 } 439 440 /** 441 * Bean property getter: <property>maxItems</property>. 442 * 443 * @return The property value, or <jk>null</jk> if it is not set. 444 */ 445 public Integer getMaxItems() { 446 return maxItems; 447 } 448 449 /** 450 * Bean property setter: <property>maxItems</property>. 451 * 452 * @param value 453 * The new value for this property. 454 * <br>Can be <jk>null</jk> to unset the property. 455 * @return This object. 456 */ 457 public HeaderInfo setMaxItems(Integer value) { 458 maxItems = value; 459 return this; 460 } 461 462 /** 463 * Bean property getter: <property>maxLength</property>. 464 * 465 * @return The property value, or <jk>null</jk> if it is not set. 466 */ 467 public Integer getMaxLength() { 468 return maxLength; 469 } 470 471 /** 472 * Bean property setter: <property>maxLength</property>. 473 * 474 * @param value 475 * The new value for this property. 476 * <br>Can be <jk>null</jk> to unset the property. 477 * @return This object. 478 */ 479 public HeaderInfo setMaxLength(Integer value) { 480 maxLength = value; 481 return this; 482 } 483 484 /** 485 * Bean property getter: <property>minimum</property>. 486 * 487 * @return The property value, or <jk>null</jk> if it is not set. 488 */ 489 public Number getMinimum() { 490 return minimum; 491 } 492 493 /** 494 * Bean property setter: <property>minimum</property>. 495 * 496 * @param value 497 * The new value for this property. 498 * <br>Can be <jk>null</jk> to unset the property. 499 * @return This object. 500 */ 501 public HeaderInfo setMinimum(Number value) { 502 minimum = value; 503 return this; 504 } 505 506 /** 507 * Bean property getter: <property>minItems</property>. 508 * 509 * @return The property value, or <jk>null</jk> if it is not set. 510 */ 511 public Integer getMinItems() { 512 return minItems; 513 } 514 515 /** 516 * Bean property setter: <property>minItems</property>. 517 * 518 * @param value 519 * The new value for this property. 520 * <br>Can be <jk>null</jk> to unset the property. 521 * @return This object. 522 */ 523 public HeaderInfo setMinItems(Integer value) { 524 minItems = value; 525 return this; 526 } 527 528 /** 529 * Bean property getter: <property>minLength</property>. 530 * 531 * @return The property value, or <jk>null</jk> if it is not set. 532 */ 533 public Integer getMinLength() { 534 return minLength; 535 } 536 537 /** 538 * Bean property setter: <property>minLength</property>. 539 * 540 * @param value 541 * The new value for this property. 542 * <br>Can be <jk>null</jk> to unset the property. 543 * @return This object. 544 */ 545 public HeaderInfo setMinLength(Integer value) { 546 minLength = value; 547 return this; 548 } 549 550 /** 551 * Bean property getter: <property>multipleOf</property>. 552 * 553 * @return The property value, or <jk>null</jk> if it is not set. 554 */ 555 public Number getMultipleOf() { 556 return multipleOf; 557 } 558 559 /** 560 * Bean property setter: <property>multipleOf</property>. 561 * 562 * @param value 563 * The new value for this property. 564 * <br>Can be <jk>null</jk> to unset the property. 565 * @return This object. 566 */ 567 public HeaderInfo setMultipleOf(Number value) { 568 multipleOf = value; 569 return this; 570 } 571 572 /** 573 * Bean property getter: <property>pattern</property>. 574 * 575 * @return The property value, or <jk>null</jk> if it is not set. 576 */ 577 public String getPattern() { 578 return pattern; 579 } 580 581 /** 582 * Bean property setter: <property>pattern</property>. 583 * 584 * @param value 585 * The new value for this property. 586 * <br>This string SHOULD be a valid regular expression. 587 * <br>Can be <jk>null</jk> to unset the property. 588 * @return This object. 589 */ 590 public HeaderInfo setPattern(String value) { 591 pattern = value; 592 return this; 593 } 594 595 /** 596 * Bean property getter: <property>$ref</property>. 597 * 598 * @return The property value, or <jk>null</jk> if it is not set. 599 */ 600 @Beanp("$ref") 601 public String getRef() { 602 return ref; 603 } 604 605 /** 606 * Bean property setter: <property>$ref</property>. 607 * 608 * @param value 609 * The new value for this property. 610 * <br>Can be <jk>null</jk> to unset the property. 611 * @return This object. 612 */ 613 @Beanp("$ref") 614 public HeaderInfo setRef(String value) { 615 ref = value; 616 return this; 617 } 618 619 /** 620 * Bean property getter: <property>type</property>. 621 * 622 * <p> 623 * The type of the object. 624 * 625 * @return The property value, or <jk>null</jk> if it is not set. 626 */ 627 public String getType() { 628 return type; 629 } 630 631 /** 632 * Bean property setter: <property>type</property>. 633 * 634 * <p> 635 * The type of the object. 636 * 637 * @param value 638 * The new value for this property. 639 * <br>Property value is required. 640 * <br>Valid values: 641 * <ul> 642 * <li><js>"string"</js> 643 * <li><js>"number"</js> 644 * <li><js>"integer"</js> 645 * <li><js>"boolean"</js> 646 * <li><js>"array"</js> 647 * </ul> 648 * @return This object. 649 */ 650 public HeaderInfo setType(String value) { 651 if (isStrict() && ! ArrayUtils.contains(value, VALID_TYPES)) 652 throw new BasicRuntimeException( 653 "Invalid value passed in to setType(String). Value=''{0}'', valid values={1}", 654 value, Json5.of(VALID_TYPES) 655 ); 656 type = value; 657 return this; 658 } 659 660 /** 661 * Bean property getter: <property>uniqueItems</property>. 662 * 663 * @return The property value, or <jk>null</jk> if it is not set. 664 */ 665 public Boolean getUniqueItems() { 666 return uniqueItems; 667 } 668 669 /** 670 * Bean property setter: <property>uniqueItems</property>. 671 * 672 * @param value 673 * The new value for this property. 674 * <br>Can be <jk>null</jk> to unset the property. 675 * @return This object. 676 */ 677 public HeaderInfo setUniqueItems(Boolean value) { 678 uniqueItems = value; 679 return this; 680 } 681 682 // <FluentSetters> 683 684 // </FluentSetters> 685 686 @Override /* SwaggerElement */ 687 public <T> T get(String property, Class<T> type) { 688 if (property == null) 689 return null; 690 switch (property) { 691 case "collectionFormat": return toType(getCollectionFormat(), type); 692 case "default": return toType(getDefault(), type); 693 case "description": return (T)getDescription(); 694 case "enum": return toType(getEnum(), type); 695 case "example": return toType(getExample(), type); 696 case "exclusiveMaximum": return toType(getExclusiveMaximum(), type); 697 case "exclusiveMinimum": return toType(getExclusiveMinimum(), type); 698 case "format": return toType(getFormat(), type); 699 case "items": return toType(getItems(), type); 700 case "maximum": return toType(getMaximum(), type); 701 case "maxItems": return toType(getMaxItems(), type); 702 case "maxLength": return toType(getMaxLength(), type); 703 case "minimum": return toType(getMinimum(), type); 704 case "minItems": return toType(getMinItems(), type); 705 case "minLength": return toType(getMinLength(), type); 706 case "multipleOf": return toType(getMultipleOf(), type); 707 case "pattern": return toType(getPattern(), type); 708 case "$ref": return toType(getRef(), type); 709 case "type": return toType(getType(), type); 710 case "uniqueItems": return toType(getUniqueItems(), type); 711 default: return super.get(property, type); 712 } 713 } 714 715 @Override /* SwaggerElement */ 716 public HeaderInfo set(String property, Object value) { 717 if (property == null) 718 return this; 719 switch (property) { 720 case "collectionFormat": return setCollectionFormat(stringify(value)); 721 case "default": return setDefault(value); 722 case "description": return setDescription(stringify(value)); 723 case "enum": return setEnum(setBuilder(Object.class).sparse().addAny(value).build()); 724 case "example": return setExample(value); 725 case "exclusiveMaximum": return setExclusiveMaximum(toBoolean(value)); 726 case "exclusiveMinimum": return setExclusiveMinimum(toBoolean(value)); 727 case "format": return setFormat(stringify(value)); 728 case "items": return setItems(toType(value, Items.class)); 729 case "maximum": return setMaximum(toNumber(value)); 730 case "maxItems": return setMaxItems(toInteger(value)); 731 case "maxLength": return setMaxLength(toInteger(value)); 732 case "minimum": return setMinimum(toNumber(value)); 733 case "minItems": return setMinItems(toInteger(value)); 734 case "minLength": return setMinLength(toInteger(value)); 735 case "multipleOf": return setMultipleOf(toNumber(value)); 736 case "pattern": return setPattern(stringify(value)); 737 case "$ref": return setRef(stringify(value)); 738 case "type": return setType(stringify(value)); 739 case "uniqueItems": return setUniqueItems(toBoolean(value)); 740 default: 741 super.set(property, value); 742 return this; 743 } 744 } 745 746 @Override /* SwaggerElement */ 747 public Set<String> keySet() { 748 Set<String> s = setBuilder(String.class) 749 .addIf(collectionFormat != null, "collectionFormat") 750 .addIf(_default != null, "default") 751 .addIf(description != null, "description") 752 .addIf(_enum != null, "enum") 753 .addIf(example != null, "example") 754 .addIf(exclusiveMaximum != null, "exclusiveMaximum") 755 .addIf(exclusiveMinimum != null, "exclusiveMinimum") 756 .addIf(format != null, "format") 757 .addIf(items != null, "items") 758 .addIf(maximum != null, "maximum") 759 .addIf(maxItems != null, "maxItems") 760 .addIf(maxLength != null, "maxLength") 761 .addIf(minimum != null, "minimum") 762 .addIf(minItems != null, "minItems") 763 .addIf(minLength != null, "minLength") 764 .addIf(multipleOf != null, "multipleOf") 765 .addIf(pattern != null, "pattern") 766 .addIf(ref != null, "$ref") 767 .addIf(type != null, "type") 768 .addIf(uniqueItems != null, "uniqueItems") 769 .build(); 770 return new MultiSet<>(s, super.keySet()); 771 772 } 773 774 /** 775 * Resolves any <js>"$ref"</js> attributes in this element. 776 * 777 * @param swagger The swagger document containing the definitions. 778 * @param refStack Keeps track of previously-visited references so that we don't cause recursive loops. 779 * @param maxDepth 780 * The maximum depth to resolve references. 781 * <br>After that level is reached, <c>$ref</c> references will be left alone. 782 * <br>Useful if you have very complex models and you don't want your swagger page to be overly-complex. 783 * @return 784 * This object with references resolved. 785 * <br>May or may not be the same object. 786 */ 787 public HeaderInfo resolveRefs(Swagger swagger, Deque<String> refStack, int maxDepth) { 788 789 if (ref != null) { 790 if (refStack.contains(ref) || refStack.size() >= maxDepth) 791 return this; 792 refStack.addLast(ref); 793 HeaderInfo r = swagger.findRef(ref, HeaderInfo.class).resolveRefs(swagger, refStack, maxDepth); 794 refStack.removeLast(); 795 return r; 796 } 797 798 if (items != null) 799 items = items.resolveRefs(swagger, refStack, maxDepth); 800 801 return this; 802 } 803}