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.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.collections.*;
024import org.apache.juneau.http.*;
025import org.apache.juneau.internal.*;
026import org.apache.juneau.json.*;
027import org.apache.juneau.utils.*;
028
029/**
030 * This is the root document object for the API specification.
031 *
032 * <ul class='seealso'>
033 *    <li class='link'>{@doc DtoSwagger}
034 * </ul>
035 */
036@Bean(bpi="swagger,info,tags,externalDocs,basePath,schemes,consumes,produces,paths,definitions,parameters,responses,securityDefinitions,security,*")
037public class Swagger extends SwaggerElement {
038
039   /** Represents a null swagger */
040   public static final Swagger NULL = new Swagger();
041
042   private static final Comparator<String> PATH_COMPARATOR = new Comparator<String>() {
043      @Override /* Comparator */
044      public int compare(String o1, String o2) {
045         return o1.replace('{', '@').compareTo(o2.replace('{', '@'));
046      }
047   };
048
049   private String
050      swagger = "2.0",
051      host,
052      basePath;
053   private Info info;
054   private ExternalDocumentation externalDocs;
055   private List<String> schemes;
056   private List<MediaType>
057      consumes,
058      produces;
059   private List<Tag> tags;
060   private List<Map<String,List<String>>> security;
061   private Map<String,OMap> definitions;
062   private Map<String,ParameterInfo> parameters;
063   private Map<String,ResponseInfo> responses;
064   private Map<String,SecurityScheme> securityDefinitions;
065   private Map<String,OperationMap> paths;
066
067   /**
068    * Default constructor.
069    */
070   public Swagger() {}
071
072   /**
073    * Copy constructor.
074    *
075    * @param copyFrom The object to copy.
076    */
077   public Swagger(Swagger copyFrom) {
078      super(copyFrom);
079
080      this.swagger = copyFrom.swagger;
081      this.host = copyFrom.host;
082      this.basePath = copyFrom.basePath;
083      this.info = copyFrom.info == null ? null : copyFrom.info.copy();
084      this.externalDocs = copyFrom.externalDocs == null ? null : copyFrom.externalDocs.copy();
085      this.schemes = newList(copyFrom.schemes);
086      this.consumes = newList(copyFrom.consumes);
087      this.produces = newList(copyFrom.produces);
088
089      if (copyFrom.tags == null) {
090         this.tags = null;
091      } else {
092         this.tags = new ArrayList<>();
093         for (Tag t : copyFrom.tags)
094            this.tags.add(t.copy());
095      }
096
097      if (copyFrom.security == null) {
098         this.security = null;
099      } else {
100         this.security = new ArrayList<>();
101         for (Map<String,List<String>> m : copyFrom.security) {
102            Map<String,List<String>> m2 = new LinkedHashMap<>();
103            for (Map.Entry<String,List<String>> e : m.entrySet())
104               m2.put(e.getKey(), newList(e.getValue()));
105            this.security.add(m2);
106         }
107      }
108
109      // TODO - Definitions are not deep copied, so they should not contain references.
110      if (copyFrom.definitions == null) {
111         this.definitions = null;
112      } else {
113         this.definitions = new LinkedHashMap<>();
114         for (Map.Entry<String,OMap> e : copyFrom.definitions.entrySet())
115            this.definitions.put(e.getKey(), new OMap(e.getValue()));
116      }
117
118      if (copyFrom.parameters == null) {
119         this.parameters = null;
120      } else {
121         this.parameters = new LinkedHashMap<>();
122         for (Map.Entry<String,ParameterInfo> e : copyFrom.parameters.entrySet())
123            this.parameters.put(e.getKey(), e.getValue().copy());
124      }
125
126      if (copyFrom.responses == null) {
127         this.responses = null;
128      } else {
129         this.responses = new LinkedHashMap<>();
130         for (Map.Entry<String,ResponseInfo> e : copyFrom.responses.entrySet())
131            this.responses.put(e.getKey(), e.getValue().copy());
132      }
133
134      if (copyFrom.securityDefinitions == null) {
135         this.securityDefinitions = null;
136      } else {
137         this.securityDefinitions = new LinkedHashMap<>();
138         for (Map.Entry<String,SecurityScheme> e : copyFrom.securityDefinitions.entrySet())
139            this.securityDefinitions.put(e.getKey(), e.getValue().copy());
140      }
141
142      if (copyFrom.paths == null) {
143         this.paths = null;
144      } else {
145         this.paths = new LinkedHashMap<>();
146         for (Map.Entry<String,OperationMap> e : copyFrom.paths.entrySet()) {
147            OperationMap m = new OperationMap();
148            for (Map.Entry<String,Operation> e2 : e.getValue().entrySet())
149               m.put(e2.getKey(), e2.getValue().copy());
150            this.paths.put(e.getKey(), m);
151         }
152      }
153   }
154
155   /**
156    * Make a deep copy of this object.
157    *
158    * @return A deep copy of this object.
159    */
160   public Swagger copy() {
161      return new Swagger(this);
162   }
163
164   /**
165    * Bean property getter:  <property>swagger</property>.
166    *
167    * <p>
168    * Specifies the Swagger Specification version being used.
169    *
170    * <p>
171    * It can be used by the Swagger UI and other clients to interpret the API listing.
172    *
173    * @return The property value, or <jk>null</jk> if it is not set.
174    */
175   public String getSwagger() {
176      return swagger;
177   }
178
179   /**
180    * Bean property setter:  <property>swagger</property>.
181    *
182    * <p>
183    * Specifies the Swagger Specification version being used.
184    *
185    * <p>
186    * It can be used by the Swagger UI and other clients to interpret the API listing.
187    *
188    * @param value
189    *    The new value for this property.
190    *    <br>Property value is required.
191    * @return This object (for method chaining).
192    */
193   public Swagger setSwagger(String value) {
194      swagger = value;
195      return this;
196   }
197
198   /**
199    * Same as {@link #setSwagger(String)}.
200    *
201    * @param value
202    *    The new value for this property.
203    *    <br>Non-String values will be converted to String using <c>toString()</c>.
204    *    <br>Can be <jk>null</jk> to unset the property.
205    * @return This object (for method chaining).
206    */
207   public Swagger swagger(Object value) {
208      return setSwagger(stringify(value));
209   }
210
211   /**
212    * Bean property getter:  <property>info</property>.
213    *
214    * <p>
215    * Provides metadata about the API.
216    *
217    * <p>
218    * The metadata can be used by the clients if needed.
219    *
220    * @return The property value, or <jk>null</jk> if it is not set.
221    */
222   public Info getInfo() {
223      return info;
224   }
225
226   /**
227    * Bean property setter:  <property>info</property>.
228    *
229    * <p>
230    * Provides metadata about the API.
231    *
232    * <p>
233    * The metadata can be used by the clients if needed.
234    *
235    * @param value
236    *    The new value for this property.
237    *    <br>Property value is required.
238    * @return This object (for method chaining).
239    */
240   public Swagger setInfo(Info value) {
241      info = value;
242      return this;
243   }
244
245   /**
246    * Same as {@link #setInfo(Info)}.
247    *
248    * @param value
249    *    The new value for this property.
250    *    <br>Valid types:
251    *    <ul>
252    *       <li>{@link Info}
253    *       <li><c>String</c> - JSON object representation of {@link Info}
254    *          <p class='bcode w800'>
255    *    <jc>// Example </jc>
256    *    info(<js>"{title:'title',description:'description',...}"</js>);
257    *          </p>
258    *    </ul>
259    *    <br>Property value is required.
260    * @return This object (for method chaining).
261    */
262   public Swagger info(Object value) {
263      return setInfo(toType(value, Info.class));
264   }
265
266   /**
267    * Bean property getter:  <property>host</property>.
268    *
269    * <p>
270    * The host (name or IP) serving the API.
271    *
272    * @return The property value, or <jk>null</jk> if it is not set.
273    */
274   public String getHost() {
275      return host;
276   }
277
278   /**
279    * Bean property setter:  <property>host</property>.
280    *
281    * <p>
282    * The host (name or IP) serving the API.
283    *
284    * @param value
285    *    The new value for this property.
286    *    <br>This MUST be the host only and does not include the scheme nor sub-paths.
287    *    <br>It MAY include a port.
288    *    <br>If the host is not included, the host serving the documentation is to be used (including the port).
289    *    <br>The host does not support {@doc ExtSwaggerPathTemplating path templating}
290    *    <br>Can be <jk>null</jk> to unset the property.
291    * @return This object (for method chaining).
292    */
293   public Swagger setHost(String value) {
294      host = value;
295      return this;
296   }
297
298   /**
299    * Same as {@link #setHost(String)}.
300    *
301    * @param value
302    *    The new value for this property.
303    *    <br>Non-String values will be converted to String using <c>toString()</c>.
304    *    <br>This MUST be the host only and does not include the scheme nor sub-paths.
305    *    <br>It MAY include a port.
306    *    <br>If the host is not included, the host serving the documentation is to be used (including the port).
307    *    <br>The host does not support {@doc ExtSwaggerPathTemplating path templating}
308    *    <br>Can be <jk>null</jk> to unset the property.
309    * @return This object (for method chaining).
310    */
311   public Swagger host(Object value) {
312      return setHost(stringify(value));
313   }
314
315   /**
316    * Bean property getter:  <property>basePath</property>.
317    *
318    * <p>
319    * The base path on which the API is served, which is relative to the <c>host</c>.
320    *
321    * @return The property value, or <jk>null</jk> if it is not set.
322    */
323   public String getBasePath() {
324      return basePath;
325   }
326
327   /**
328    * Bean property setter:  <property>basePath</property>.
329    *
330    * <p>
331    * The base path on which the API is served, which is relative to the <c>host</c>.
332    *
333    * @param value
334    *    The new value for this property.
335    *    <br>If it is not included, the API is served directly under the <c>host</c>.
336    *    <br>The value MUST start with a leading slash (/).
337    *    <br>The <c>basePath</c> does not support {@doc ExtSwaggerPathTemplating path templating}.
338    *    <br>Can be <jk>null</jk> to unset the property.
339    * @return This object (for method chaining).
340    */
341   public Swagger setBasePath(String value) {
342      basePath = value;
343      return this;
344   }
345
346   /**
347    * Same as {@link #setBasePath(String)}.
348    *
349    * @param value
350    *    The new value for this property.
351    *    <br>Non-String values will be converted to String using <c>toString()</c>.
352    *    <br>If it is not included, the API is served directly under the <c>host</c>.
353    *    <br>The value MUST start with a leading slash (/).
354    *    <br>The <c>basePath</c> does not support {@doc ExtSwaggerPathTemplating path templating}.
355    *    <br>Can be <jk>null</jk> to unset the property.
356    * @return This object (for method chaining).
357    */
358   public Swagger basePath(Object value) {
359      return setBasePath(stringify(value));
360   }
361
362   /**
363    * Bean property getter:  <property>schemes</property>.
364    *
365    * <p>
366    * The transfer protocol of the API.
367    *
368    * <p>
369    * If the <c>schemes</c> is not included, the default scheme to be used is the one used to access the Swagger
370    * definition itself.
371    *
372    * @return The property value, or <jk>null</jk> if it is not set.
373    */
374   public List<String> getSchemes() {
375      return schemes;
376   }
377
378   /**
379    * Bean property setter:  <property>schemes</property>.
380    *
381    * <p>
382    * The transfer protocol of the API.
383    *
384    * <p>
385    * If the <c>schemes</c> is not included, the default scheme to be used is the one used to access the Swagger
386    * definition itself.
387    *
388    * @param value
389    *    The new value for this property.
390    *    <br>Valid values:
391    *    <ul>
392    *       <li><js>"http"</js>
393    *       <li><js>"https"</js>
394    *       <li><js>"ws"</js>
395    *       <li><js>"wss"</js>
396    *    </ul>
397    *    <br>Can be <jk>null</jk> to unset the property.
398    * @return This object (for method chaining).
399    */
400   public Swagger setSchemes(Collection<String> value) {
401      schemes = newList(value);
402      return this;
403   }
404
405   /**
406    * Adds one or more values to the <property>schemes</property> property.
407    *
408    * <p>
409    * The transfer protocol of the API.
410    *
411    * <p>
412    * Values MUST be from the list:  <js>"http"</js>, <js>"https"</js>, <js>"ws"</js>, <js>"wss"</js>.
413    * If the <c>schemes</c> is not included, the default scheme to be used is the one used to access the Swagger
414    * definition itself.
415    *
416    * @param values
417    *    The values to add to this property.
418    *    <br>Valid values:
419    *    <ul>
420    *       <li><js>"http"</js>
421    *       <li><js>"https"</js>
422    *       <li><js>"ws"</js>
423    *       <li><js>"wss"</js>
424    *    </ul>
425    *    <br>Ignored if <jk>null</jk>.
426    * @return This object (for method chaining).
427    */
428   public Swagger addSchemes(Collection<String> values) {
429      schemes = addToList(schemes, values);
430      return this;
431   }
432
433   /**
434    * Same as {@link #addSchemes(Collection)}.
435    *
436    * @param values
437    *    The values to add to this property.
438    *    <br>Valid types:
439    *    <ul>
440    *       <li><c>Collection&lt;String&gt;</c>
441    *       <li><c>String</c> - JSON array representation of <c>Collection&lt;String&gt;</c>
442    *          <p class='bcode w800'>
443    *    <jc>// Example </jc>
444    *    schemes(<js>"['scheme1','scheme2']"</js>);
445    *       </p>
446    *       <li><c>String</c> - Individual values
447    *          <p class='bcode w800'>
448    *    <jc>// Example </jc>
449    *    schemes(<js>"scheme1"</js>, <js>"scheme2"</js>);
450    *       </p>
451    *    </ul>
452    * @return This object (for method chaining).
453    */
454   public Swagger schemes(Object...values) {
455      schemes = addToList(schemes, values, String.class);
456      return this;
457   }
458
459   /**
460    * Bean property getter:  <property>consumes</property>.
461    *
462    * <p>
463    * A list of MIME types the APIs can consume.
464    *
465    * <p>
466    * This is global to all APIs but can be overridden on specific API calls.
467    *
468    * @return The property value, or <jk>null</jk> if it is not set.
469    */
470   public List<MediaType> getConsumes() {
471      return consumes;
472   }
473
474   /**
475    * Bean property setter:  <property>consumes</property>.
476    *
477    * <p>
478    * A list of MIME types the APIs can consume.
479    *
480    * <p>
481    * This is global to all APIs but can be overridden on specific API calls.
482    *
483    * @param value
484    *    The new value for this property.
485    *    <br>Value MUST be as described under {@doc ExtSwaggerMimeTypes}.
486    *    <br>Can be <jk>null</jk> to unset the property.
487    * @return This object (for method chaining).
488    */
489   public Swagger setConsumes(Collection<MediaType> value) {
490      consumes = newList(value);
491      return this;
492   }
493
494   /**
495    * Adds one or more values to the <property>consumes</property> property.
496    *
497    * <p>
498    * A list of MIME types the operation can consume.
499    * This overrides the <c>consumes</c> definition at the Swagger Object.
500    * An empty value MAY be used to clear the global definition.
501    * Value MUST be as described under {@doc ExtSwaggerMimeTypes}.
502    *
503    * @param values
504    *    The values to add to this property.
505    *    <br>Values MUST be as described under {@doc ExtSwaggerMimeTypes}.
506    *    <br>Ignored if <jk>null</jk>.
507    * @return This object (for method chaining).
508    */
509   public Swagger addConsumes(Collection<MediaType> values) {
510      consumes = addToList(consumes, values);
511      return this;
512   }
513
514   /**
515    * Adds one or more values to the <property>consumes</property> property.
516    *
517    * @param values
518    *    The values to add to this property.
519    *    <br>Valid types:
520    *    <ul>
521    *       <li>{@link MediaType}
522    *       <li><c>Collection&lt;{@link MediaType}|String&gt;</c>
523    *       <li><c>String</c> - JSON array representation of <c>Collection&lt;{@link MediaType}&gt;</c>
524    *          <p class='bcode w800'>
525    *    <jc>// Example </jc>
526    *    consumes(<js>"['text/json']"</js>);
527    *          </p>
528    *       <li><c>String</c> - Individual values
529    *          <p class='bcode w800'>
530    *    <jc>// Example </jc>
531    *    consumes(<js>"text/json"</js>);
532    *          </p>
533    *    </ul>
534    *    <br>Ignored if <jk>null</jk>.
535    * @return This object (for method chaining).
536    */
537   public Swagger consumes(Object...values) {
538      consumes = addToList(consumes, values, MediaType.class);
539      return this;
540   }
541
542   /**
543    * Bean property getter:  <property>produces</property>.
544    *
545    * <p>
546    * A list of MIME types the APIs can produce.
547    *
548    * <p>
549    * This is global to all APIs but can be overridden on specific API calls.
550    *
551    * @return The property value, or <jk>null</jk> if it is not set.
552    */
553   public List<MediaType> getProduces() {
554      return produces;
555   }
556
557   /**
558    * Bean property setter:  <property>produces</property>.
559    *
560    * <p>
561    * A list of MIME types the APIs can produce.
562    *
563    * <p>
564    * This is global to all APIs but can be overridden on specific API calls.
565    *
566    * @param value
567    *    The new value for this property.
568    *    <br>Value MUST be as described under {@doc ExtSwaggerMimeTypes}.
569    *    <br>Can be <jk>null</jk> to unset the property.
570    * @return This object (for method chaining).
571    */
572   public Swagger setProduces(Collection<MediaType> value) {
573      produces = newList(value);
574      return this;
575   }
576
577   /**
578    * Adds one or more values to the <property>produces</property> property.
579    *
580    * <p>
581    * A list of MIME types the APIs can produce.
582    *
583    * <p>
584    * This is global to all APIs but can be overridden on specific API calls.
585    *
586    * @param values
587    *    The values to add to this property.
588    *    <br>Value MUST be as described under {@doc ExtSwaggerMimeTypes}.
589    *    <br>Can be <jk>null</jk> to unset the property.
590    * @return This object (for method chaining).
591    */
592   public Swagger addProduces(Collection<MediaType> values) {
593      produces = addToList(produces, values);
594      return this;
595   }
596
597   /**
598    * Adds one or more values to the <property>produces</property> property.
599    *
600    * @param values
601    *    The values to add to this property.
602    *    <br>Valid types:
603    *    <ul>
604    *       <li>{@link MediaType}
605    *       <li><c>Collection&lt;{@link MediaType}|String&gt;</c>
606    *       <li><c>String</c> - JSON array representation of <c>Collection&lt;{@link MediaType}&gt;</c>
607    *          <p class='bcode w800'>
608    *    <jc>// Example </jc>
609    *    consumes(<js>"['text/json']"</js>);
610    *          </p>
611    *       <li><c>String</c> - Individual values
612    *          <p class='bcode w800'>
613    *    <jc>// Example </jc>
614    *    consumes(<js>"text/json"</js>);
615    *          </p>
616    *    </ul>
617    *    <br>Ignored if <jk>null</jk>.
618    * @return This object (for method chaining).
619    */
620   public Swagger produces(Object...values) {
621      produces = addToList(produces, values, MediaType.class);
622      return this;
623   }
624
625   /**
626    * Bean property getter:  <property>paths</property>.
627    *
628    * <p>
629    * The available paths and operations for the API.
630    *
631    * @return The property value, or <jk>null</jk> if it is not set.
632    */
633   public Map<String,OperationMap> getPaths() {
634      return paths;
635   }
636
637   /**
638    * Shortcut for calling <c>getPaths().get(path);</c>
639    *
640    * @param path The path (e.g. <js>"/foo"</js>).
641    * @return The operation map for the specified path, or <jk>null</jk> if it doesn't exist.
642    */
643   public OperationMap getPath(String path) {
644      return getPaths().get(path);
645   }
646
647   /**
648    * Shortcut for calling <c>getPaths().get(path).get(operation);</c>
649    *
650    * @param path The path (e.g. <js>"/foo"</js>).
651    * @param operation The HTTP operation (e.g. <js>"get"</js>).
652    * @return The operation for the specified path and operation id, or <jk>null</jk> if it doesn't exist.
653    */
654   public Operation getOperation(String path, String operation) {
655      OperationMap om = getPath(path);
656      if (om == null)
657         return null;
658      return om.get(operation);
659   }
660
661   /**
662    * Shortcut for calling <c>getPaths().get(path).get(operation).getResponse(status);</c>
663    *
664    * @param path The path (e.g. <js>"/foo"</js>).
665    * @param operation The HTTP operation (e.g. <js>"get"</js>).
666    * @param status The HTTP response status (e.g. <js>"200"</js>).
667    * @return The operation for the specified path and operation id, or <jk>null</jk> if it doesn't exist.
668    */
669   public ResponseInfo getResponseInfo(String path, String operation, Object status) {
670      OperationMap om = getPath(path);
671      if (om == null)
672         return null;
673      Operation op = om.get(operation);
674      if (op == null)
675         return null;
676      return op.getResponse(status);
677   }
678
679   /**
680    * Bean property setter:  <property>paths</property>.
681    *
682    * <p>
683    * The available paths and operations for the API.
684    *
685    * @param value
686    *    The new value for this property.
687    *    <br>Property value is required.
688    * @return This object (for method chaining).
689    */
690   public Swagger setPaths(Map<String,OperationMap> value) {
691      paths = newSortedMap(value, PATH_COMPARATOR);
692      return this;
693   }
694
695   /**
696    * Adds one or more values to the <property>produces</property> property.
697    *
698    * <p>
699    * A list of MIME types the APIs can produce.
700    *
701    * <p>
702    * This is global to all APIs but can be overridden on specific API calls.
703    *
704    * @param values
705    *    The values to add to this property.
706    *    <br>Ignored if <jk>null</jk>.
707    * @return This object (for method chaining).
708    */
709   public Swagger addPaths(Map<String,OperationMap> values) {
710      paths = addToSortedMap(paths, values, PATH_COMPARATOR);
711      return this;
712   }
713
714   /**
715    * Adds a single value to the <property>paths</property> property.
716    *
717    * @param path The path template.
718    * @param methodName The HTTP method name.
719    * @param operation The operation that describes the path.
720    * @return This object (for method chaining).
721    */
722   public Swagger path(String path, String methodName, Operation operation) {
723      if (paths == null)
724         paths = new TreeMap<>(PATH_COMPARATOR);
725      OperationMap p = paths.get(path);
726      if (p == null) {
727         p = new OperationMap();
728         paths.put(path, p);
729      }
730      p.put(methodName, operation);
731      return this;
732   }
733
734   /**
735    * Adds one or more values to the <property>paths</property> property.
736    *
737    * @param values
738    *    The values to add to this property.
739    *    <br>Valid types:
740    *    <ul>
741    *       <li><c>Map&lt;String,Map&lt;String,{@link Operation}&gt;|String&gt;</c>
742    *       <li><c>String</c> - JSON object representation of <c>Map&lt;String,Map&lt;String,{@link Operation}&gt;&gt;</c>
743    *          <p class='bcode w800'>
744    *    <jc>// Example </jc>
745    *    paths(<js>"{'foo':{'get':{operationId:'operationId',...}}}"</js>);
746    *          </p>
747    *    </ul>
748    *    <br>Ignored if <jk>null</jk>.
749    * @return This object (for method chaining).
750    */
751   @SuppressWarnings({ "unchecked", "rawtypes" })
752   public Swagger paths(Object...values) {
753      if (paths == null)
754         paths = new TreeMap<>(PATH_COMPARATOR);
755      paths = addToMap((Map)paths, values, String.class, Map.class, String.class, Operation.class);
756      return this;
757   }
758
759   /**
760    * Bean property getter:  <property>definitions</property>.
761    *
762    * <p>
763    * An object to hold data types produced and consumed by operations.
764    *
765    * @return The property value, or <jk>null</jk> if it is not set.
766    */
767   public Map<String,OMap> getDefinitions() {
768      return definitions;
769   }
770
771   /**
772    * Bean property setter:  <property>definitions</property>.
773    *
774    * <p>
775    * An object to hold data types produced and consumed by operations.
776    *
777    * @param value
778    *    The new value for this property.
779    *    <br>Can be <jk>null</jk> to unset the property.
780    * @return This object (for method chaining).
781    */
782   public Swagger setDefinitions(Map<String,OMap> value) {
783      definitions = newMap(value);
784      return this;
785   }
786
787   /**
788    * Adds one or more values to the <property>definitions</property> property.
789    *
790    * <p>
791    * An object to hold data types produced and consumed by operations.
792    *
793    * @param values
794    *    The values to add to this property.
795    *    <br>Ignored if <jk>null</jk>.
796    * @return This object (for method chaining).
797    */
798   public Swagger addDefinitions(Map<String,OMap> values) {
799      definitions = addToMap(definitions, values);
800      return this;
801   }
802
803   /**
804    * Adds a single value to the <property>definitions</property> property.
805    *
806    * @param name A definition name.
807    * @param schema The schema that the name defines.
808    * @return This object (for method chaining).
809    */
810   public Swagger definition(String name, OMap schema) {
811      definitions = addToMap(definitions, name, schema);
812      return this;
813   }
814
815   /**
816    * Adds one or more values to the <property>definitions</property> property.
817    *
818    * @param values
819    *    The values to add to this property.
820    *    <br>Valid types:
821    *    <ul>
822    *       <li><c>Map&lt;String,Map&lt;String,{@link SchemaInfo}&gt;|String&gt;</c>
823    *       <li><c>String</c> - JSON object representation of <c>Map&lt;String,Map&lt;String,{@link SchemaInfo}&gt;&gt;</c>
824    *          <p class='bcode w800'>
825    *    <jc>// Example </jc>
826    *    definitions(<js>"{'foo':{'bar':{format:'format',...}}}"</js>);
827    *          </p>
828    *    </ul>
829    *    <br>Ignored if <jk>null</jk>.
830    * @return This object (for method chaining).
831    */
832   public Swagger definitions(Object...values) {
833      definitions = addToMap(definitions, values, String.class, OMap.class);
834      return this;
835   }
836
837   /**
838    * Convenience method for testing whether this Swagger has one or more definitions defined.
839    *
840    * @return <jk>true</jk> if this Swagger has one or more definitions defined.
841    */
842   public boolean hasDefinitions() {
843      return definitions != null && ! definitions.isEmpty();
844   }
845
846   /**
847    * Bean property getter:  <property>parameters</property>.
848    *
849    * <p>
850    * An object to hold parameters that can be used across operations.
851    *
852    * <p>
853    * This property does not define global parameters for all operations.
854    *
855    * @return The property value, or <jk>null</jk> if it is not set.
856    */
857   public Map<String,ParameterInfo> getParameters() {
858      return parameters;
859   }
860
861   /**
862    * Bean property setter:  <property>parameters</property>.
863    *
864    * <p>
865    * An object to hold parameters that can be used across operations.
866    *
867    * <p>
868    * This property does not define global parameters for all operations.
869    *
870    * @param value
871    *    The new value for this property.
872    *    <br>Can be <jk>null</jk> to unset the property.
873    * @return This object (for method chaining).
874    */
875   public Swagger setParameters(Map<String,ParameterInfo> value) {
876      parameters = newMap(value);
877      return this;
878   }
879
880   /**
881    * Adds one or more values to the <property>parameters</property> property.
882    *
883    * <p>
884    * An object to hold parameters that can be used across operations.
885    *
886    * <p>
887    * This property does not define global parameters for all operations.
888    *
889    * @param values
890    *    The values to add to this property.
891    *    <br>Ignored if <jk>null</jk>.
892    * @return This object (for method chaining).
893    */
894   public Swagger addParameters(Map<String,ParameterInfo> values) {
895      parameters = addToMap(parameters, values);
896      return this;
897   }
898
899   /**
900    * Adds a single value to the <property>parameter</property> property.
901    *
902    * @param name The parameter name.
903    * @param parameter The parameter definition.
904    * @return This object (for method chaining).
905    */
906   public Swagger parameter(String name, ParameterInfo parameter) {
907      parameters = addToMap(parameters, name, parameter);
908      return this;
909   }
910
911   /**
912    * Adds one or more values to the <property>properties</property> property.
913    *
914    * @param values
915    *    The values to add to this property.
916    *    <br>Valid types:
917    *    <ul>
918    *       <li><c>Map&lt;String,{@link ParameterInfo}|String&gt;</c>
919    *       <li><c>String</c> - JSON object representation of <c>Map&lt;String,{@link ParameterInfo}&gt;</c>
920    *          <p class='bcode w800'>
921    *    <jc>// Example </jc>
922    *    parameters(<js>"{'foo':{name:'name',...}}"</js>);
923    *          </p>
924    *    </ul>
925    *    <br>Ignored if <jk>null</jk>.
926    * @return This object (for method chaining).
927    */
928   public Swagger parameters(Object...values) {
929      parameters = addToMap(parameters, values, String.class, ParameterInfo.class);
930      return this;
931   }
932
933   /**
934    * Convenience method for calling <c>getPath(path).get(method).getParameter(in,name);</c>
935    *
936    * @param path The HTTP path.
937    * @param method The HTTP method.
938    * @param in The parameter type.
939    * @param name The parameter name.
940    * @return The parameter information or <jk>null</jk> if not found.
941    */
942   public ParameterInfo getParameterInfo(String path, String method, String in, String name) {
943      OperationMap om = getPath(path);
944      if (om != null) {
945         Operation o = om.get(method);
946         if (o != null) {
947            return o.getParameter(in, name);
948         }
949      }
950      return null;
951   }
952
953   /**
954    * Bean property getter:  <property>responses</property>.
955    *
956    * <p>
957    * An object to hold responses that can be used across operations.
958    *
959    * <p>
960    * This property does not define global responses for all operations.
961    *
962    * @return The property value, or <jk>null</jk> if it is not set.
963    */
964   public Map<String,ResponseInfo> getResponses() {
965      return responses;
966   }
967
968   /**
969    * Bean property setter:  <property>responses</property>.
970    *
971    * <p>
972    * An object to hold responses that can be used across operations.
973    *
974    * <p>
975    * This property does not define global responses for all operations.
976    *
977    * @param value
978    *    The new value for this property.
979    *    <br>Can be <jk>null</jk> to unset the property.
980    * @return This object (for method chaining).
981    */
982   public Swagger setResponses(Map<String,ResponseInfo> value) {
983      responses = newMap(value);
984      return this;
985   }
986
987   /**
988    * Adds one or more values to the <property>responses</property> property.
989    *
990    * <p>
991    * An object to hold responses that can be used across operations.
992    *
993    * <p>
994    * This property does not define global responses for all operations.
995    *
996    * @param values
997    *    The values to add to this property.
998    *    <br>Ignored if <jk>null</jk>.
999    * @return This object (for method chaining).
1000    */
1001   public Swagger addResponses(Map<String,ResponseInfo> values) {
1002      responses = addToMap(responses, values);
1003      return this;
1004   }
1005
1006   /**
1007    * Adds a single value to the <property>responses</property> property.
1008    *
1009    * @param name The response name.
1010    * @param response The response definition.
1011    * @return This object (for method chaining).
1012    */
1013   public Swagger response(String name, ResponseInfo response) {
1014      responses = addToMap(responses, name, response);
1015      return this;
1016   }
1017
1018   /**
1019    * Adds one or more values to the <property>properties</property> property.
1020    *
1021    * @param values
1022    *    The values to add to this property.
1023    *    <br>Valid types:
1024    *    <ul>
1025    *       <li><c>Map&lt;String,{@link ResponseInfo}|String&gt;</c>
1026    *       <li><c>String</c> - JSON object representation of <c>Map&lt;String,{@link ResponseInfo}&gt;</c>
1027    *          <p class='bcode w800'>
1028    *    <jc>// Example </jc>
1029    *    responses(<js>"{'foo':{description:'description',...}}"</js>);
1030    *          </p>
1031    *    </ul>
1032    *    <br>Ignored if <jk>null</jk>.
1033    * @return This object (for method chaining).
1034    */
1035   public Swagger responses(Object...values) {
1036      responses = addToMap(responses, values, String.class, ResponseInfo.class);
1037      return this;
1038   }
1039
1040   /**
1041    * Bean property getter:  <property>securityDefinitions</property>.
1042    *
1043    * <p>
1044    * Security scheme definitions that can be used across the specification.
1045    *
1046    * @return The property value, or <jk>null</jk> if it is not set.
1047    */
1048   public Map<String,SecurityScheme> getSecurityDefinitions() {
1049      return securityDefinitions;
1050   }
1051
1052   /**
1053    * Bean property setter:  <property>securityDefinitions</property>.
1054    *
1055    * <p>
1056    * Security scheme definitions that can be used across the specification.
1057    *
1058    * @param value
1059    *    The new value for this property.
1060    *    <br>Can be <jk>null</jk> to unset the property.
1061    * @return This object (for method chaining).
1062    */
1063   public Swagger setSecurityDefinitions(Map<String,SecurityScheme> value) {
1064      securityDefinitions = newMap(value);
1065      return this;
1066   }
1067
1068   /**
1069    * Adds one or more values to the <property>securityDefinitions</property> property.
1070    *
1071    * <p>
1072    * Security scheme definitions that can be used across the specification.
1073    *
1074    * @param values
1075    *    The values to add to this property.
1076    *    <br>Ignored if <jk>null</jk>.
1077    * @return This object (for method chaining).
1078    */
1079   public Swagger addSecurityDefinitions(Map<String,SecurityScheme> values) {
1080      securityDefinitions = addToMap(securityDefinitions, values);
1081      return this;
1082   }
1083
1084   /**
1085    * Adds a single value to the <property>securityDefinitions</property> property.
1086    *
1087    * @param name A security name.
1088    * @param securityScheme A security schema.
1089    * @return This object (for method chaining).
1090    */
1091   public Swagger securityDefinition(String name, SecurityScheme securityScheme) {
1092      securityDefinitions = addToMap(securityDefinitions, name, securityScheme);
1093      return this;
1094   }
1095
1096   /**
1097    * Adds one or more values to the <property>securityDefinitions</property> property.
1098    *
1099    * @param values
1100    *    The values to add to this property.
1101    *    <br>Valid types:
1102    *    <ul>
1103    *       <li><c>Map&lt;String,{@link SecurityScheme}|String&gt;</c>
1104    *       <li><c>String</c> - JSON object representation of <c>Map&lt;String,{@link SecurityScheme}&gt;</c>
1105    *          <p class='bcode w800'>
1106    *    <jc>// Example </jc>
1107    *    securityDefinitions(<js>"{'foo':{name:'name',...}}"</js>);
1108    *          </p>
1109    *    </ul>
1110    *    <br>Ignored if <jk>null</jk>.
1111    * @return This object (for method chaining).
1112    */
1113   public Swagger securityDefinitions(Object...values) {
1114      securityDefinitions = addToMap(securityDefinitions, values, String.class, SecurityScheme.class);
1115      return this;
1116   }
1117
1118   /**
1119    * Bean property getter:  <property>security</property>.
1120    *
1121    * <p>
1122    * A declaration of which security schemes are applied for the API as a whole.
1123    *
1124    * <p>
1125    * The list of values describes alternative security schemes that can be used (that is, there is a logical OR
1126    * between the security requirements).
1127    * <br>Individual operations can override this definition.
1128    *
1129    * @return The property value, or <jk>null</jk> if it is not set.
1130    */
1131   public List<Map<String,List<String>>> getSecurity() {
1132      return security;
1133   }
1134
1135   /**
1136    * Bean property setter:  <property>security</property>.
1137    *
1138    * <p>
1139    * A declaration of which security schemes are applied for the API as a whole.
1140    *
1141    * <p>
1142    * The list of values describes alternative security schemes that can be used (that is, there is a logical OR
1143    * between the security requirements).
1144    * <br>Individual operations can override this definition.
1145    *
1146    * @param value
1147    *    The new value for this property.
1148    *    <br>Can be <jk>null</jk> to unset the property.
1149    * @return This object (for method chaining).
1150    */
1151   public Swagger setSecurity(Collection<Map<String,List<String>>> value) {
1152      security = newList(value);
1153      return this;
1154   }
1155
1156   /**
1157    * Adds one or more values to the <property>security</property> property.
1158    *
1159    * <p>
1160    * A declaration of which security schemes are applied for the API as a whole.
1161    *
1162    * <p>
1163    * The list of values describes alternative security schemes that can be used (that is, there is a logical OR
1164    * between the security requirements).
1165    * <br>Individual operations can override this definition.
1166    *
1167    * @param values
1168    *    The values to add to this property.
1169    *    <br>Ignored if <jk>null</jk>.
1170    * @return This object (for method chaining).
1171    */
1172   public Swagger addSecurity(Collection<Map<String,List<String>>> values) {
1173      security = addToList(security, values);
1174      return this;
1175   }
1176
1177
1178   /**
1179    * Adds a single value to the <property>securityDefinitions</property> property.
1180    *
1181    * @param scheme The security scheme that applies to this operation
1182    * @param alternatives
1183    *    The list of values describes alternative security schemes that can be used (that is, there is a logical OR between the security requirements).
1184    * @return This object (for method chaining).
1185    */
1186   public Swagger security(String scheme, String...alternatives) {
1187      Map<String,List<String>> m = new LinkedHashMap<>();
1188      m.put(scheme, Arrays.asList(alternatives));
1189      return addSecurity(Collections.singleton(m));
1190   }
1191
1192   /**
1193    * Adds one or more values to the <property>securityDefinitions</property> property.
1194    *
1195    * @param values
1196    *    The values to add to this property.
1197    *    <br>Valid types:
1198    *    <ul>
1199    *       <li><c>Collection&lt;Map&lt;String,List&lt;String&gt;&gt;&gt;</c>
1200    *       <li><c>String</c> - JSON array representation of <c>Collection&lt;Map&lt;String,List&lt;String&gt;&gt;&gt;</c>
1201    *          <p class='bcode w800'>
1202    *    <jc>// Example </jc>
1203    *    securities(<js>"[{...}]"</js>);
1204    *          </p>
1205    *       <li><c>String</c> - JSON object representation of <c>Map&lt;String,List&lt;String&gt;&gt;</c>
1206    *          <p class='bcode w800'>
1207    *    <jc>// Example </jc>
1208    *    securities(<js>"{...}"</js>);
1209    *          </p>
1210    *    </ul>
1211    *    <br>Ignored if <jk>null</jk>.
1212    * @return This object (for method chaining).
1213    */
1214   @SuppressWarnings({ "unchecked", "rawtypes" })
1215   public Swagger securities(Object...values) {
1216      security = addToList((List)security, values, Map.class, String.class, List.class, String.class);
1217      return this;
1218   }
1219
1220   /**
1221    * Bean property getter:  <property>tags</property>.
1222    *
1223    * <p>
1224    * A list of tags used by the specification with additional metadata.
1225    *
1226    * @return The property value, or <jk>null</jk> if it is not set.
1227    */
1228   public List<Tag> getTags() {
1229      return tags;
1230   }
1231
1232   /**
1233    * Bean property setter:  <property>tags</property>.
1234    *
1235    * <p>
1236    * A list of tags used by the specification with additional metadata.
1237    *
1238    * @param value
1239    *    The new value for this property.
1240    *    <br>The order of the tags can be used to reflect on their order by the parsing tools.
1241    *    <br>Not all tags that are used by the {@doc ExtSwaggerOperationObject Operation Object} must be declared.
1242    *    <br>The tags that are not declared may be organized randomly or based on the tools' logic.
1243    *    <br>Each tag name in the list MUST be unique.
1244    *    <br>Can be <jk>null</jk> to unset the property.
1245    * @return This object (for method chaining).
1246    */
1247   public Swagger setTags(Collection<Tag> value) {
1248      tags = newList(value);
1249      return this;
1250   }
1251
1252   /**
1253    * Adds one or more values to the <property>security</property> property.
1254    *
1255    * <p>
1256    * A list of tags used by the specification with additional metadata.
1257    *
1258    * @param values
1259    *    The values to add to this property.
1260    *    <br>The order of the tags can be used to reflect on their order by the parsing tools.
1261    *    <br>Not all tags that are used by the {@doc ExtSwaggerOperationObject Operation Object} must be declared.
1262    *    <br>The tags that are not declared may be organized randomly or based on the tools' logic.
1263    *    <br>Each tag name in the list MUST be unique.
1264    *    <br>Ignored if <jk>null</jk>.
1265    * @return This object (for method chaining).
1266    */
1267   public Swagger addTags(Collection<Tag> values) {
1268      tags = addToList(tags, values);
1269      return this;
1270   }
1271
1272
1273   /**
1274    * Adds one or more values to the <property>tags</property> property.
1275    *
1276    * @param values
1277    *    The values to add to this property.
1278    *    <br>Valid types:
1279    *    <ul>
1280    *       <li>{@link Tag}
1281    *       <li><c>Collection&lt;{@link Tag}|String&gt;</c>
1282    *       <li><c>{@link Tag}[]</c>
1283    *       <li><c>String</c> - JSON array representation of <c>Collection&lt;{@link Tag}&gt;</c>
1284    *          <p class='bcode w800'>
1285    *    <jc>// Example </jc>
1286    *    tags(<js>"[{name:'name',description:'description',...}]"</js>);
1287    *          </p>
1288    *       <li><c>String</c> - JSON object representation of <c>{@link Tag}</c>
1289    *          <p class='bcode w800'>
1290    *    <jc>// Example </jc>
1291    *    tags(<js>"{name:'name',description:'description',...}"</js>);
1292    *          </p>
1293    *    </ul>
1294    *    <br>Ignored if <jk>null</jk>.
1295    * @return This object (for method chaining).
1296    */
1297   public Swagger tags(Object...values) {
1298      tags = addToList(tags, values, Tag.class);
1299      return this;
1300   }
1301
1302   /**
1303    * Convenience method for testing whether this Swagger has one or more tags defined.
1304    *
1305    * @return <jk>true</jk> if this Swagger has one or more tags defined.
1306    */
1307   public boolean hasTags() {
1308      return tags != null && ! tags.isEmpty();
1309   }
1310
1311   /**
1312    * Bean property getter:  <property>externalDocs</property>.
1313    *
1314    * <p>
1315    * Additional external documentation.
1316    *
1317    * @return The property value, or <jk>null</jk> if it is not set.
1318    */
1319   public ExternalDocumentation getExternalDocs() {
1320      return externalDocs;
1321   }
1322
1323   /**
1324    * Bean property setter:  <property>externalDocs</property>.
1325    *
1326    * <p>
1327    * Additional external documentation.
1328    *
1329    * @param value
1330    *    The new value for this property.
1331    *    <br>Can be <jk>null</jk> to unset the property.
1332    * @return This object (for method chaining).
1333    */
1334   public Swagger setExternalDocs(ExternalDocumentation value) {
1335      externalDocs = value;
1336      return this;
1337   }
1338
1339   /**
1340    * Same as {@link #setExternalDocs(ExternalDocumentation)}.
1341    *
1342    * @param value
1343    *    The new value for this property.
1344    *    <br>Valid types:
1345    *    <ul>
1346    *       <li>{@link ExternalDocumentation}
1347    *       <li><c>String</c> - JSON object representation of {@link ExternalDocumentation}
1348    *          <p class='bcode w800'>
1349    *    <jc>// Example </jc>
1350    *    externalDocs(<js>"{description:'description',url:'url'}"</js>);
1351    *          </p>
1352    *    </ul>
1353    *    <br>Can be <jk>null</jk> to unset the property.
1354    * @return This object (for method chaining).
1355    */
1356   public Swagger externalDocs(Object value) {
1357      return setExternalDocs(toType(value, ExternalDocumentation.class));
1358   }
1359
1360   @Override /* SwaggerElement */
1361   public <T> T get(String property, Class<T> type) {
1362      if (property == null)
1363         return null;
1364      switch (property) {
1365         case "swagger": return toType(getSwagger(), type);
1366         case "info": return toType(getInfo(), type);
1367         case "host": return toType(getHost(), type);
1368         case "basePath": return toType(getBasePath(), type);
1369         case "schemes": return toType(getSchemes(), type);
1370         case "consumes": return toType(getConsumes(), type);
1371         case "produces": return toType(getProduces(), type);
1372         case "paths": return toType(getPaths(), type);
1373         case "definitions": return toType(getDefinitions(), type);
1374         case "parameters": return toType(getParameters(), type);
1375         case "responses": return toType(getResponses(), type);
1376         case "securityDefinitions": return toType(getSecurityDefinitions(), type);
1377         case "security": return toType(getSecurity(), type);
1378         case "tags": return toType(getTags(), type);
1379         case "externalDocs": return toType(getExternalDocs(), type);
1380         default: return super.get(property, type);
1381      }
1382   }
1383
1384   @Override /* SwaggerElement */
1385   public Swagger set(String property, Object value) {
1386      if (property == null)
1387         return this;
1388      switch (property) {
1389         case "swagger": return swagger(value);
1390         case "info": return info(value);
1391         case "host": return host(value);
1392         case "basePath": return basePath(value);
1393         case "schemes": return setSchemes(null).schemes(value);
1394         case "consumes": return setConsumes(null).consumes(value);
1395         case "produces": return setProduces(null).produces(value);
1396         case "paths": return setPaths(null).paths(value);
1397         case "definitions": return setDefinitions(null).definitions(value);
1398         case "parameters": return setParameters(null).parameters(value);
1399         case "responses": return setResponses(null).responses(value);
1400         case "securityDefinitions": return setSecurityDefinitions(null).securityDefinitions(value);
1401         case "security": return setSecurity(null).securities(value);
1402         case "tags": return setTags(null).tags(value);
1403         case "externalDocs": return externalDocs(value);
1404         default:
1405            super.set(property, value);
1406            return this;
1407      }
1408   }
1409
1410   @Override /* SwaggerElement */
1411   public Set<String> keySet() {
1412      ASet<String> s = ASet.<String>of()
1413         .aif(swagger != null, "swagger")
1414         .aif(info != null, "info")
1415         .aif(host != null, "host")
1416         .aif(basePath != null, "basePath")
1417         .aif(schemes != null, "schemes")
1418         .aif(consumes != null, "consumes")
1419         .aif(produces != null, "produces")
1420         .aif(paths != null, "paths")
1421         .aif(definitions != null, "definitions")
1422         .aif(parameters != null, "parameters")
1423         .aif(responses != null, "responses")
1424         .aif(securityDefinitions != null, "securityDefinitions")
1425         .aif(security != null, "security")
1426         .aif(tags != null, "tags")
1427         .aif(externalDocs != null, "externalDocs");
1428      return new MultiSet<>(s, super.keySet());
1429   }
1430
1431   @Override /* Object */
1432   public String toString() {
1433      return JsonSerializer.DEFAULT.toString(this);
1434   }
1435
1436   /**
1437    * Resolves a <js>"$ref"</js> tags to nodes in this swagger document.
1438    *
1439    * @param ref The ref tag value.
1440    * @param c The class to convert the reference to.
1441    * @return The referenced node, or <jk>null</jk> if the ref was <jk>null</jk> or empty or not found.
1442    */
1443   public <T> T findRef(String ref, Class<T> c) {
1444      if (isEmpty(ref))
1445         return null;
1446      if (! ref.startsWith("#/"))
1447         throw new RuntimeException("Unsupported reference:  '" + ref + '"');
1448      try {
1449         return new PojoRest(this).get(ref.substring(1), c);
1450      } catch (Exception e) {
1451         throw new BeanRuntimeException(e, c, "Reference ''{0}'' could not be converted to type ''{1}''.", ref, c.getName());
1452      }
1453   }
1454}