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 &gt; juneau-rest-server &gt; 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}