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.openapi3;
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 org.apache.juneau.annotation.*;
020import org.apache.juneau.dto.swagger.Swagger;
021import org.apache.juneau.internal.*;
022
023import java.util.*;
024
025/**
026 * Describes a single HTTP header.
027 *
028 * <h5 class='section'>Example:</h5>
029 * <p class='bcode'>
030 *    <jc>// Construct using SwaggerBuilder.</jc>
031 *    HeaderInfo x = <jsm>headerInfo</jsm>(<js>"integer"</js>).description(<js>"The number of allowed requests in the current period"</js>);
032 *
033 *    <jc>// Serialize using JsonSerializer.</jc>
034 *    String json = JsonSerializer.<jsf>DEFAULT</jsf>.toString(x);
035 *
036 *    <jc>// Or just use toString() which does the same as above.</jc>
037 *    String json = x.toString();
038 * </p>
039 * <p class='bcode'>
040 *    <jc>// Output</jc>
041 *    {
042 *       <js>"description"</js>: <js>"The number of allowed requests in the current period"</js>,
043 *       <js>"type"</js>: <js>"integer"</js>
044 *    }
045 * </p>
046 */
047@Bean(properties="description,explode,deprecated,allowEmptyValue,allowReserved,schema,example,examples,$ref,*")
048@SuppressWarnings({"unchecked"})
049@FluentSetters
050public class HeaderInfo extends OpenApiElement {
051
052   private String
053      description,
054      ref;
055   private Boolean
056      required,
057      explode,
058      deprecated,
059      allowEmptyValue,
060      allowReserved;
061   private SchemaInfo schema;
062   private Object example;
063   private Map<String,Example> examples;
064
065
066   /**
067    * Default constructor.
068    */
069   public HeaderInfo() {}
070
071   /**
072    * Copy constructor.
073    *
074    * @param copyFrom The object to copy.
075    */
076   public HeaderInfo(HeaderInfo copyFrom) {
077      super(copyFrom);
078
079      this.description = copyFrom.description;
080      this.example = copyFrom.example;
081      this.allowEmptyValue = copyFrom.allowEmptyValue;
082      this.schema = copyFrom.schema;
083      this.allowReserved = copyFrom.allowReserved;
084      this.required = copyFrom.required;
085      this.ref = copyFrom.ref;
086      this.explode = copyFrom.explode;
087      this.deprecated = copyFrom.deprecated;
088      if (copyFrom.examples == null)
089         this.examples = null;
090      else
091         this.examples = new LinkedHashMap<>();
092         for (Map.Entry<String,Example> e : copyFrom.examples.entrySet())
093            this.examples.put(e.getKey(), e.getValue().copy());
094   }
095
096   /**
097    * Make a deep copy of this object.
098    *
099    * @return A deep copy of this object.
100    */
101   public HeaderInfo copy() {
102      return new HeaderInfo(this);
103   }
104
105   @Override /* OpenApiElement */
106   protected HeaderInfo strict() {
107      super.strict();
108      return this;
109   }
110
111   /**
112    * Bean property getter:  <property>description</property>.
113    *
114    * <p>
115    * A short description of the header.
116    *
117    * @return The property value, or <jk>null</jk> if it is not set.
118    */
119   public String getDescription() {
120      return description;
121   }
122
123   /**
124    * Bean property setter:  <property>description</property>.
125    *
126    * <p>
127    * A short description of the header.
128    *
129    * @param value
130    *    The new value for this property.
131    *    <br>Can be <jk>null</jk> to unset the property.
132    * @return This object
133    */
134   public HeaderInfo setDescription(String value) {
135      description = value;
136      return this;
137   }
138
139   /**
140    * Bean property getter:  <property>required</property>.
141    *
142    * <p>
143    * The type of the object.
144    *
145    * @return The property value, or <jk>null</jk> if it is not set.
146    */
147   public Boolean getRequired() {
148      return required;
149   }
150
151   /**
152    * Bean property setter:  <property>required</property>.
153    *
154    * <p>
155    * The type of the object.
156    *
157    * @param value
158    *    The new value for this property.
159    *    <br>Property value is required.
160    *    <br>Valid values:
161    *    <ul>
162    *       <li><js>"string"</js>
163    *       <li><js>"number"</js>
164    *       <li><js>"integer"</js>
165    *       <li><js>"boolean"</js>
166    *       <li><js>"array"</js>
167    *    </ul>
168    * @return This object
169    */
170   public HeaderInfo setRequired(Boolean value) {
171      required = value;
172      return this;
173   }
174
175   /**
176    * Bean property getter:  <property>required</property>.
177    *
178    * <p>
179    * The type of the object.
180    *
181    * @return The property value, or <jk>null</jk> if it is not set.
182    */
183   public Boolean getExplode() {
184      return explode;
185   }
186
187   /**
188    * Bean property setter:  <property>explode</property>.
189    *
190    * <p>
191    * The type of the object.
192    *
193    * @param value
194    *    The new value for this property.
195    * @return This object
196    */
197   public HeaderInfo setExplode(Boolean value) {
198      explode = value;
199      return this;
200   }
201
202   /**
203    * Bean property getter:  <property>deprecated</property>.
204    *
205    * <p>
206    * The type of the object.
207    *
208    * @return The property value, or <jk>null</jk> if it is not set.
209    */
210   public Boolean getDeprecated() {
211      return deprecated;
212   }
213
214   /**
215    * Bean property setter:  <property>deprecated</property>.
216    *
217    * <p>
218    * The type of the object.
219    *
220    * @param value
221    *    The new value for this property.
222    * @return This object
223    */
224   public HeaderInfo setDeprecated(Boolean value) {
225      deprecated = value;
226      return this;
227   }
228
229   /**
230    * Bean property getter:  <property>allowEmptyValue</property>.
231    *
232    * <p>
233    * The type of the object.
234    *
235    * @return The property value, or <jk>null</jk> if it is not set.
236    */
237   public Boolean getAllowEmptyValue() {
238      return allowEmptyValue;
239   }
240
241   /**
242    * Bean property setter:  <property>allowEmptyValue</property>.
243    *
244    * <p>
245    * The type of the object.
246    *
247    * @param value
248    *    The new value for this property.
249    * @return This object
250    */
251   public HeaderInfo setAllowEmptyValue(Boolean value) {
252      allowEmptyValue = value;
253      return this;
254   }
255
256   /**
257    * Bean property getter:  <property>allowReserved</property>.
258    *
259    * <p>
260    * The type of the object.
261    *
262    * @return The property value, or <jk>null</jk> if it is not set.
263    */
264   public Boolean getAllowReserved() {
265      return allowReserved;
266   }
267
268   /**
269    * Bean property setter:  <property>allowReserved</property>.
270    *
271    * <p>
272    * The type of the object.
273    *
274    * @param value
275    *    The new value for this property.
276    * @return This object
277    */
278   public HeaderInfo setAllowReserved(Boolean value) {
279      allowReserved = value;
280      return this;
281   }
282
283   /**
284    * Bean property getter:  <property>schema</property>.
285    *
286    * @return The property value, or <jk>null</jk> if it is not set.
287    */
288   public SchemaInfo getSchema() {
289      return schema;
290   }
291
292   /**
293    * Bean property setter:  <property>schema</property>.
294    *
295    * @param value
296    *    The new value for this property.
297    *    <br>Can be <jk>null</jk> to unset the property.
298    * @return This object
299    */
300   public HeaderInfo setSchema(SchemaInfo value) {
301      schema = value;
302      return this;
303   }
304
305   /**
306    * Bean property getter:  <property>$ref</property>.
307    *
308    * @return The property value, or <jk>null</jk> if it is not set.
309    */
310   @Beanp("$ref")
311   public String getRef() {
312      return ref;
313   }
314
315   /**
316    * Bean property setter:  <property>$ref</property>.
317    *
318    * @param value
319    *    The new value for this property.
320    *    <br>Can be <jk>null</jk> to unset the property.
321    * @return This object
322    */
323   @Beanp("$ref")
324   public HeaderInfo setRef(String value) {
325      ref = value;
326      return this;
327   }
328
329   /**
330    * Bean property getter:  <property>x-example</property>.
331    *
332    * @return The property value, or <jk>null</jk> if it is not set.
333    */
334   @Beanp("x-example")
335   public Object getExample() {
336      return example;
337   }
338
339   /**
340    * Bean property setter:  <property>examples</property>.
341    *
342    * @param value
343    *    The new value for this property.
344    *    <br>Can be <jk>null</jk> to unset the property.
345    * @return This object
346    */
347   @Beanp("x-example")
348   public HeaderInfo setExample(Object value) {
349      example = value;
350      return this;
351   }
352
353   /**
354    * Bean property getter:  <property>examples</property>.
355    *
356    * <p>
357    * The list of possible responses as they are returned from executing this operation.
358    *
359    * @return The property value, or <jk>null</jk> if it is not set.
360    */
361   public Map<String,Example> getExamples() {
362      return examples;
363   }
364
365   /**
366    * Bean property setter:  <property>headers</property>.
367    *
368    * <p>
369    * A list of examples that are sent with the response.
370    *
371    * @param value
372    *    The new value for this property.
373    *    <br>Can be <jk>null</jk> to unset the property.
374    * @return This object
375    */
376   public HeaderInfo setExamples(Map<String,Example> value) {
377      examples = copyOf(value);
378      return this;
379   }
380
381   /**
382    * Adds a single value to the <property>examples</property> property.
383    *
384    * @param name The example name.
385    * @param example The example.
386    * @return This object
387    */
388   public HeaderInfo addExample(String name, Example example) {
389      examples = mapBuilder(examples).sparse().add(name, example).build();
390      return this;
391   }
392
393   // <FluentSetters>
394
395   // </FluentSetters>
396
397   @Override /* OpenApiElement */
398   public <T> T get(String property, Class<T> type) {
399      if (property == null)
400         return null;
401      switch (property) {
402         case "description": return (T)getDescription();
403         case "required": return toType(getRequired(), type);
404         case "explode": return toType(getExplode(), type);
405         case "deprecated": return toType(getDeprecated(), type);
406         case "allowEmptyValue": return toType(getAllowEmptyValue(), type);
407         case "allowReserved": return toType(getAllowReserved(), type);
408         case "$ref": return toType(getRef(), type);
409         case "schema": return toType(getSchema(), type);
410         case "x-example": return toType(getExample(), type);
411         case "examples": return toType(getExamples(), type);
412         default: return super.get(property, type);
413      }
414   }
415
416   @Override /* OpenApiElement */
417   public HeaderInfo set(String property, Object value) {
418      if (property == null)
419         return this;
420      switch (property) {
421         case "description": return setDescription(stringify(value));
422         case "required": return setRequired(toBoolean(value));
423         case "explode": return setExplode(toBoolean(value));
424         case "deprecated": return setDeprecated(toBoolean(value));
425         case "allowEmptyValue": return setAllowEmptyValue(toBoolean(value));
426         case "$ref": return setRef(stringify(value));
427         case "schema": return setSchema(toType(value, SchemaInfo.class));
428         case "x-example": return setExample(stringify(value));
429         case "examples": return setExamples(mapBuilder(String.class,Example.class).sparse().addAny(value).build());
430         default:
431            super.set(property, value);
432            return this;
433      }
434   }
435
436   @Override /* SwaggerElement */
437   public Set<String> keySet() {
438      Set<String> s = setBuilder(String.class)
439         .addIf(description != null, "description")
440         .addIf(required != null, "required")
441         .addIf(explode != null, "explode")
442         .addIf(deprecated != null, "deprecated")
443         .addIf(allowEmptyValue != null, "allowEmptyValue")
444         .addIf(ref != null, "$ref")
445         .addIf(allowReserved != null, "allowReserved")
446         .addIf(schema != null, "schema")
447         .addIf(example != null, "example")
448         .addIf(examples != null, "examples")
449         .build();
450      return new MultiSet<>(s, super.keySet());
451
452   }
453
454   /**
455    * Resolves any <js>"$ref"</js> attributes in this element.
456    *
457    * @param swagger The swagger document containing the definitions.
458    * @param refStack Keeps track of previously-visited references so that we don't cause recursive loops.
459    * @param maxDepth
460    *    The maximum depth to resolve references.
461    *    <br>After that level is reached, <code>$ref</code> references will be left alone.
462    *    <br>Useful if you have very complex models and you don't want your swagger page to be overly-complex.
463    * @return
464    *    This object with references resolved.
465    *    <br>May or may not be the same object.
466    */
467   public HeaderInfo resolveRefs(Swagger swagger, Deque<String> refStack, int maxDepth) {
468
469      if (ref != null) {
470         if (refStack.contains(ref) || refStack.size() >= maxDepth)
471            return this;
472         refStack.addLast(ref);
473         HeaderInfo r = swagger.findRef(ref, HeaderInfo.class).resolveRefs(swagger, refStack, maxDepth);
474         refStack.removeLast();
475         return r;
476      }
477      return this;
478   }
479}