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