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