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.annotation.*;
021import org.apache.juneau.http.*;
022import org.apache.juneau.internal.*;
023import org.apache.juneau.utils.*;
024
025/**
026 * Describes a single API operation on a path.
027 *
028 * <h5 class='section'>Example:</h5>
029 * <p class='bcode w800'>
030 *    <jc>// Construct using SwaggerBuilder.</jc>
031 *    Operation x = <jsm>operation</jsm>()
032 *       .tags(<js>"pet"</js>)
033 *       .summary(<js>"Updates a pet in the store with form data"</js>)
034 *       .description(<js>""</js>)
035 *       .operationId(<js>"updatePetWithForm"</js>)
036 *       .consumes(<js>"application/x-www-form-urlencoded"</js>)
037 *       .produces(<js>"application/json"</js>, <js>"application/xml"</js>)
038 *       .parameters(
039 *          <jsm>parameter</jsm>()
040 *             .name(<js>"petId"</js>)
041 *             .in(<js>"path"</js>)
042 *             .description(<js>"ID of pet that needs to be updated"</js>)
043 *             .required(<jk>true</jk>)
044 *             .type(<js>"string"</js>),
045 *          <jsm>parameter</jsm>()
046 *             .name(<js>"name"</js>)
047 *             .in(<js>"formData"</js>)
048 *             .description(<js>"Updated name of the pet"</js>)
049 *             .required(<jk>false</jk>)
050 *             .type(<js>"string"</js>),
051 *          <jsm>parameter</jsm>()
052 *             .name(<js>"status"</js>)
053 *             .in(<js>"formData"</js>)
054 *             .description(<js>"Updated status of the pet"</js>)
055 *             .required(<jk>false</jk>)
056 *             .type(<js>"string"</js>)
057 *       )
058 *       .response(200, <jsm>responseInfo</jsm>(<js>"Pet updated."</js>))
059 *       .response(405, <jsm>responseInfo</jsm>(<js>"Invalid input."</js>))
060 *       .security(<js>"petstore_auth"</js>, <js>"write:pets"</js>, <js>"read:pets"</js>);
061 *
062 *    <jc>// Serialize using JsonSerializer.</jc>
063 *    String json = JsonSerializer.<jsf>DEFAULT</jsf>.toString(x);
064 *
065 *    <jc>// Or just use toString() which does the same as above.</jc>
066 *    String json = x.toString();
067 * </p>
068 * <p class='bcode w800'>
069 *    <jc>// Output</jc>
070 *    {
071 *       <js>"tags"</js>: [
072 *          <js>"pet"</js>
073 *       ],
074 *       <js>"summary"</js>: <js>"Updates a pet in the store with form data"</js>,
075 *       <js>"description"</js>: <js>""</js>,
076 *       <js>"operationId"</js>: <js>"updatePetWithForm"</js>,
077 *       <js>"consumes"</js>: [
078 *          <js>"application/x-www-form-urlencoded"</js>
079 *       ],
080 *       <js>"produces"</js>: [
081 *          <js>"application/json"</js>,
082 *          <js>"application/xml"</js>
083 *       ],
084 *       <js>"parameters"</js>: [
085 *          {
086 *             <js>"name"</js>: <js>"petId"</js>,
087 *             <js>"in"</js>: <js>"path"</js>,
088 *             <js>"description"</js>: <js>"ID of pet that needs to be updated"</js>,
089 *             <js>"required"</js>: <jk>true</jk>,
090 *             <js>"type"</js>: <js>"string"</js>
091 *          },
092 *          {
093 *             <js>"name"</js>: <js>"name"</js>,
094 *             <js>"in"</js>: <js>"formData"</js>,
095 *             <js>"description"</js>: <js>"Updated name of the pet"</js>,
096 *             <js>"required"</js>: <jk>false</jk>,
097 *             <js>"type"</js>: <js>"string"</js>
098 *          },
099 *          {
100 *             <js>"name"</js>: <js>"status"</js>,
101 *             <js>"in"</js>: <js>"formData"</js>,
102 *             <js>"description"</js>: <js>"Updated status of the pet"</js>,
103 *             <js>"required"</js>: <jk>false</jk>,
104 *             <js>"type"</js>: <js>"string"</js>
105 *          }
106 *       ],
107 *       <js>"responses"</js>: {
108 *          <js>"200"</js>: {
109 *             <js>"description"</js>: <js>"Pet updated."</js>
110 *          },
111 *          <js>"405"</js>: {
112 *             <js>"description"</js>: <js>"Invalid input"</js>
113 *          }
114 *       },
115 *       <js>"security"</js>: [
116 *          {
117 *             <js>"petstore_auth"</js>: [
118 *                <js>"write:pets"</js>,
119 *                <js>"read:pets"</js>
120 *             ]
121 *          }
122 *       ]
123 *    }
124 * </p>
125 *
126 * <h5 class='section'>See Also:</h5>
127 * <ul class='doctree'>
128 *    <li class='link'>{@doc juneau-dto.Swagger}
129 * </ul>
130 */
131@Bean(properties="operationId,summary,description,tags,externalDocs,consumes,produces,parameters,responses,schemes,deprecated,security,*")
132public class Operation extends SwaggerElement {
133
134   private String
135      summary,
136      description,
137      operationId;
138   private Boolean deprecated;
139   private ExternalDocumentation externalDocs;
140   private List<String>
141      tags,
142      schemes;
143   private List<MediaType>
144      consumes,
145      produces;
146   private List<ParameterInfo> parameters;
147   private List<Map<String,List<String>>> security;
148   private Map<String,ResponseInfo> responses;
149
150   /**
151    * Default constructor.
152    */
153   public Operation() {}
154
155   /**
156    * Copy constructor.
157    *
158    * @param copyFrom The object to copy.
159    */
160   public Operation(Operation copyFrom) {
161      super(copyFrom);
162
163      this.summary = copyFrom.summary;
164      this.description = copyFrom.description;
165      this.operationId = copyFrom.operationId;
166      this.deprecated = copyFrom.deprecated;
167      this.externalDocs = copyFrom.externalDocs == null ? null : copyFrom.externalDocs.copy();
168      this.tags = newList(copyFrom.tags);
169      this.schemes = newList(copyFrom.schemes);
170      this.consumes = newList(copyFrom.consumes);
171      this.produces = newList(copyFrom.produces);
172
173      if (copyFrom.parameters == null) {
174         this.parameters = null;
175      } else {
176         this.parameters = new ArrayList<>();
177         for (ParameterInfo p : copyFrom.parameters)
178            this.parameters.add(p.copy());
179      }
180
181      if (copyFrom.security == null) {
182         this.security = null;
183      } else {
184         this.security = new ArrayList<>();
185         for (Map<String,List<String>> m : copyFrom.security) {
186            Map<String,List<String>> m2 = new LinkedHashMap<>();
187            for (Map.Entry<String,List<String>> e : m.entrySet())
188               m2.put(e.getKey(), newList(e.getValue()));
189            this.security.add(m2);
190         }
191      }
192
193      if (copyFrom.responses == null) {
194         this.responses = null;
195      } else {
196         this.responses = new LinkedHashMap<>();
197         for (Map.Entry<String,ResponseInfo> e : copyFrom.responses.entrySet())
198            this.responses.put(e.getKey(), e.getValue().copy());
199      }
200   }
201
202   /**
203    * Make a deep copy of this object.
204    *
205    * @return A deep copy of this object.
206    */
207   public Operation copy() {
208      return new Operation(this);
209   }
210
211   /**
212    * Bean property getter:  <property>tags</property>.
213    *
214    * <p>
215    * A list of tags for API documentation control.
216    * <br>Tags can be used for logical grouping of operations by resources or any other qualifier.
217    *
218    * @return The property value, or <jk>null</jk> if it is not set.
219    */
220   public List<String> getTags() {
221      return tags;
222   }
223
224   /**
225    * Bean property setter:  <property>tags</property>.
226    *
227    * <p>
228    * A list of tags for API documentation control.
229    * <br>Tags can be used for logical grouping of operations by resources or any other qualifier.
230    *
231    * @param value
232    *    The new value for this property.
233    *    <br>Can be <jk>null</jk> to unset the property.
234    * @return This object (for method chaining).
235    */
236   public Operation setTags(Collection<String> value) {
237      tags = newList(value);
238      return this;
239   }
240
241   /**
242    * Adds one or more values to the <property>tags</property> property.
243    *
244    * <p>
245    * A list of tags for API documentation control.
246    * <br>Tags can be used for logical grouping of operations by resources or any other qualifier.
247    *
248    * @param value
249    *    The values to add to this property.
250    *    <br>Ignored if <jk>null</jk>.
251    * @return This object (for method chaining).
252    */
253   public Operation addTags(Collection<String> value) {
254      tags = addToList(tags, value);
255      return this;
256   }
257
258   /**
259    * Same as {@link #addTags(Collection)}.
260    *
261    * @param values
262    *    The values to add to this property.
263    *    <br>Valid types:
264    *    <ul>
265    *       <li><code>Collection&lt;String&gt;</code>
266    *       <li><code>String</code> - JSON array representation of <code>Collection&lt;String&gt;</code>
267    *          <h5 class='figure'>Example:</h5>
268    *          <p class='bcode w800'>
269    *    tags(<js>"['foo','bar']"</js>);
270    *          </p>
271    *       <li><code>String</code> - Individual values
272    *          <h5 class='figure'>Example:</h5>
273    *          <p class='bcode w800'>
274    *    tags(<js>"foo"</js>, <js>"bar"</js>);
275    *          </p>
276    *    </ul>
277    * @return This object (for method chaining).
278    */
279   public Operation tags(Object...values) {
280      tags = addToList(tags, values, String.class);
281      return this;
282   }
283
284   /**
285    * Bean property getter:  <property>summary</property>.
286    *
287    * <p>
288    * A short summary of what the operation does.
289    *
290    * @return The property value, or <jk>null</jk> if it is not set.
291    */
292   public String getSummary() {
293      return summary;
294   }
295
296   /**
297    * Bean property setter:  <property>summary</property>.
298    *
299    * <p>
300    * A short summary of what the operation does.
301    *
302    * @param value
303    *    The new value for this property.
304    *    <br>Can be <jk>null</jk> to unset the property.
305    * @return This object (for method chaining).
306    */
307   public Operation setSummary(String value) {
308      summary = value;
309      return this;
310   }
311
312   /**
313    * Same as {@link #setSummary(String)}.
314    *
315    * @param value
316    *    The new value for this property.
317    *    <br>Non-String values will be converted to String using <code>toString()</code>.
318    *    <br>Can be <jk>null</jk> to unset the property.
319    * @return This object (for method chaining).
320    */
321   public Operation summary(Object value) {
322      return setSummary(toStringVal(value));
323   }
324
325   /**
326    * Bean property getter:  <property>description</property>.
327    *
328    * <p>
329    * A verbose explanation of the operation behavior.
330    *
331    * @return The property value, or <jk>null</jk> if it is not set.
332    */
333   public String getDescription() {
334      return description;
335   }
336
337   /**
338    * Bean property setter:  <property>description</property>.
339    *
340    * <p>
341    * A verbose explanation of the operation behavior.
342    *
343    * @param value
344    *    The new value for this property.
345    *    <br>{@doc GFM} can be used for rich text representation.
346    *    <br>Can be <jk>null</jk> to unset the property.
347    * @return This object (for method chaining).
348    */
349   public Operation setDescription(String value) {
350      description = value;
351      return this;
352   }
353
354   /**
355    * Same as {@link #setDescription(String)}.
356    *
357    * @param value
358    *    The new value for this property.
359    *    <br>Non-String values will be converted to String using <code>toString()</code>.
360    *    <br>{@doc GFM} can be used for rich text representation.
361    *    <br>Can be <jk>null</jk> to unset the property.
362    * @return This object (for method chaining).
363    */
364   public Operation description(Object value) {
365      return setDescription(toStringVal(value));
366   }
367
368   /**
369    * Bean property getter:  <property>externalDocs</property>.
370    *
371    * <p>
372    * Additional external documentation for this operation.
373    *
374    * @return The property value, or <jk>null</jk> if it is not set.
375    */
376   public ExternalDocumentation getExternalDocs() {
377      return externalDocs;
378   }
379
380   /**
381    * Bean property setter:  <property>externalDocs</property>.
382    *
383    * <p>
384    * Additional external documentation for this operation.
385    *
386    * @param value
387    *    The values to add to this property.
388    *    <br>Can be <jk>null</jk> to unset the property.
389    * @return This object (for method chaining).
390    */
391   public Operation setExternalDocs(ExternalDocumentation value) {
392      externalDocs = value;
393      return this;
394   }
395
396   /**
397    * Same as {@link #setExternalDocs(ExternalDocumentation)}.
398    *
399    * @param value
400    *    The new value for this property.
401    *    <br>Valid types:
402    *    <ul>
403    *       <li>{@link ExternalDocumentation}
404    *       <li><code>String</code> - JSON object representation of {@link ExternalDocumentation}
405    *          <h5 class='figure'>Example:</h5>
406    *          <p class='bcode w800'>
407    *    externalDocs(<js>"{description:'description',url:'url'}"</js>);
408    *          </p>
409    *    </ul>
410    *    <br>Can be <jk>null</jk> to unset the property.
411    * @return This object (for method chaining).
412    */
413   public Operation externalDocs(Object value) {
414      return setExternalDocs(toType(value, ExternalDocumentation.class));
415   }
416
417   /**
418    * Bean property getter:  <property>operationId</property>.
419    *
420    * <p>
421    * Unique string used to identify the operation.
422    *
423    * @return The property value, or <jk>null</jk> if it is not set.
424    */
425   public String getOperationId() {
426      return operationId;
427   }
428
429   /**
430    * Bean property setter:  <property>operationId</property>.
431    *
432    * <p>
433    * Unique string used to identify the operation.
434    *
435    * @param value
436    *    The new value for this property.
437    *    <br>The id MUST be unique among all operations described in the API.
438    *    <br>Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, it is recommended to
439    *    follow common programming naming conventions.
440    *    <br>Can be <jk>null</jk> to unset the property.
441    * @return This object (for method chaining).
442    */
443   public Operation setOperationId(String value) {
444      operationId = value;
445      return this;
446   }
447
448   /**
449    * Same as {@link #setOperationId(String)}.
450    *
451    * @param value
452    *    The new value for this property.
453    *    <br>The id MUST be unique among all operations described in the API.
454    *    <br>Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, it is recommended to
455    *    follow common programming naming conventions.
456    *    <br>Non-String values will be converted to String using <code>toString()</code>.
457    *    <br>Can be <jk>null</jk> to unset the property.
458    * @return This object (for method chaining).
459    */
460   public Operation operationId(Object value) {
461      return setOperationId(toStringVal(value));
462   }
463
464   /**
465    * Bean property getter:  <property>consumes</property>.
466    *
467    * <p>
468    * A list of MIME types the operation can consume.
469    *
470    * <p>
471    * This overrides the <code>consumes</code> definition at the Swagger Object.
472    * <br>An empty value MAY be used to clear the global definition.
473    *
474    * @return The property value, or <jk>null</jk> if it is not set.
475    */
476   public List<MediaType> getConsumes() {
477      return consumes;
478   }
479
480   /**
481    * Bean property setter:  <property>consumes</property>.
482    *
483    * <p>
484    * A list of MIME types the operation can consume.
485    *
486    * <p>
487    * This overrides the <code>consumes</code> definition at the Swagger Object.
488    * <br>An empty value MAY be used to clear the global definition.
489    *
490    * @param value
491    *    The new value for this property.
492    *    <br>Values MUST be as described under {@doc SwaggerMimeTypes}.
493    *    <br>Can be <jk>null</jk> to unset the property.
494    * @return This object (for method chaining).
495    */
496   public Operation setConsumes(Collection<MediaType> value) {
497      consumes = newList(value);
498      return this;
499   }
500
501   /**
502    * Adds one or more values to the <property>consumes</property> property.
503    *
504    * <p>
505    * A list of MIME types the operation can consume.
506    *
507    * <p>
508    * This overrides the <code>consumes</code> definition at the Swagger Object.
509    * <br>An empty value MAY be used to clear the global definition.
510    *
511    * @param value
512    *    The values to add to this property.
513    *    <br>Values MUST be as described under {@doc SwaggerMimeTypes}.
514    *    <br>Ignored if <jk>null</jk>.
515    * @return This object (for method chaining).
516    */
517   public Operation addConsumes(Collection<MediaType> value) {
518      consumes = addToList(consumes, value);
519      return this;
520   }
521
522   /**
523    * Adds one or more values to the <property>consumes</property> property.
524    *
525    * @param values
526    *    The values to add to this property.
527    *    <br>Valid types:
528    *    <ul>
529    *       <li>{@link MediaType}
530    *       <li><code>Collection&lt;{@link MediaType}|String&gt;</code>
531    *       <li><code>{@link MediaType}[]</code>
532    *       <li><code>String</code> - JSON array representation of <code>Collection&lt;{@link MediaType}&gt;</code>
533    *          <h5 class='figure'>Example:</h5>
534    *          <p class='bcode w800'>
535    *    consumes(<js>"['text/json']"</js>);
536    *          </p>
537    *       <li><code>String</code> - Individual values
538    *          <h5 class='figure'>Example:</h5>
539    *          <p class='bcode w800'>
540    *    consumes(<js>"text/json"</js>);
541    *          </p>
542    *    </ul>
543    *    <br>Ignored if <jk>null</jk>.
544    * @return This object (for method chaining).
545    */
546   public Operation consumes(Object...values) {
547      consumes = addToList(consumes, values, MediaType.class);
548      return this;
549   }
550
551   /**
552    * Bean property getter:  <property>produces</property>.
553    *
554    * <p>
555    * A list of MIME types the operation can produce.
556    *
557    * <p>
558    * This overrides the <code>produces</code> definition at the Swagger Object.
559    * <br>An empty value MAY be used to clear the global definition.
560    *
561    * @return The property value, or <jk>null</jk> if it is not set.
562    */
563   public List<MediaType> getProduces() {
564      return produces;
565   }
566
567   /**
568    * Bean property setter:  <property>produces</property>.
569    *
570    * <p>
571    * A list of MIME types the operation can produce.
572    *
573    * <p>
574    * This overrides the <code>produces</code> definition at the Swagger Object.
575    * <br>An empty value MAY be used to clear the global definition.
576    *
577    * @param value
578    *    The values to add to this property.
579    *    <br>Value MUST be as described under {@doc SwaggerMimeTypes}.
580    *    <br>Can be <jk>null</jk> to unset the property.
581    * @return This object (for method chaining).
582    */
583   public Operation setProduces(Collection<MediaType> value) {
584      produces = newList(value);
585      return this;
586   }
587
588   /**
589    * Adds one or more values to the <property>produces</property> property.
590    *
591    * <p>
592    * A list of MIME types the operation can produces.
593    *
594    * <p>
595    * This overrides the <code>produces</code> definition at the Swagger Object.
596    * <br>An empty value MAY be used to clear the global definition.
597    *
598    * @param value
599    *    The values to add to this property.
600    *    <br>Ignored if <jk>null</jk>.
601    * @return This object (for method chaining).
602    */
603   public Operation addProduces(Collection<MediaType> value) {
604      produces = addToList(produces, value);
605      return this;
606   }
607
608   /**
609    * Same as {@link #addProduces(Collection)}.
610    *
611    * @param values
612    *    The values to add to this property.
613    *    <br>Valid types:
614    *    <ul>
615    *       <li>{@link MediaType}
616    *       <li><code>Collection&lt;{@link MediaType}|String&gt;</code>
617    *       <li><code>{@link MediaType}[]</code>
618    *       <li><code>String</code> - JSON array representation of <code>Collection&lt;{@link MediaType}&gt;</code>
619    *          <h5 class='figure'>Example:</h5>
620    *          <p class='bcode w800'>
621    *    produces(<js>"['text/json']"</js>);
622    *          </p>
623    *       <li><code>String</code> - Individual values
624    *          <h5 class='figure'>Example:</h5>
625    *          <p class='bcode w800'>
626    *    produces(<js>"text/json"</js>);
627    *          </p>
628    *    </ul>
629    *    <br>Ignored if <jk>null</jk>.
630    * @return This object (for method chaining).
631    */
632   public Operation produces(Object...values) {
633      produces = addToList(produces, values, MediaType.class);
634      return this;
635   }
636
637   /**
638    * Bean property getter:  <property>parameters</property>.
639    *
640    * <p>
641    * A list of parameters that are applicable for this operation.
642    *
643    * <h5 class='section'>Notes:</h5>
644    * <ul class='spaced-list'>
645    *    <li>
646    *       If a parameter is already defined at the {@doc SwaggerPathItemObject Path Item},
647    *       the new definition will override it, but can never remove it.
648    *    <li>
649    *       The list MUST NOT include duplicated parameters.
650    *    <li>
651    *       A unique parameter is defined by a combination of a <code>name</code> and <code>location</code>.
652    *    <li>
653    *       The list can use the {@doc SwaggerReferenceObject}
654    *       to link to parameters that are defined at the {@doc SwaggerParameterObject Swagger Object's parameters}.
655    *    <li>
656    *       There can be one <js>"body"</js> parameter at most.
657    * </ul>
658    *
659    * @return The property value, or <jk>null</jk> if it is not set.
660    */
661   public List<ParameterInfo> getParameters() {
662      return parameters;
663   }
664
665   /**
666    * Returns the parameter with the specified type and name.
667    *
668    * @param in The parameter in.
669    * @param name The parameter name.  Can be <jk>null</jk> for parameter type <code>body</code>.
670    * @return The matching parameter info, or <jk>null</jk> if not found.
671    */
672   public ParameterInfo getParameter(String in, String name) {
673      if (parameters != null)
674         for (ParameterInfo pi : parameters)
675            if (StringUtils.isEquals(pi.getIn(), in))
676               if (StringUtils.isEquals(pi.getName(), name) || "body".equals(pi.getIn()))
677                  return pi;
678      return null;
679   }
680
681   /**
682    * Bean property setter:  <property>parameters</property>.
683    *
684    * <p>
685    * A list of parameters that are applicable for this operation.
686    *
687    * <h5 class='section'>Notes:</h5>
688    * <ul class='spaced-list'>
689    *    <li>
690    *       If a parameter is already defined at the {@doc SwaggerPathItemObject Path Item},
691    *       the new definition will override it, but can never remove it.
692    *    <li>
693    *       The list MUST NOT include duplicated parameters.
694    *    <li>
695    *       A unique parameter is defined by a combination of a <code>name</code> and <code>location</code>.
696    *    <li>
697    *       The list can use the {@doc SwaggerReferenceObject}
698    *       to link to parameters that are defined at the {@doc SwaggerParameterObject Swagger Object's parameters}.
699    *    <li>
700    *       There can be one <js>"body"</js> parameter at most.
701    * </ul>
702    *
703    * @param value
704    *    The new value for this property.
705    *    <br>Can be <jk>null</jk> to unset the property.
706    * @return This object (for method chaining).
707    */
708   public Operation setParameters(Collection<ParameterInfo> value) {
709      parameters = newList(value);
710      return this;
711   }
712
713   /**
714    * Adds one or more values to the <property>parameters</property> property.
715    *
716    * <p>
717    * A list of parameters that are applicable for this operation.
718    *
719    * <h5 class='section'>Notes:</h5>
720    * <ul class='spaced-list'>
721    *    <li>
722    *       If a parameter is already defined at the {@doc SwaggerPathItemObject Path Item},
723    *       the new definition will override it, but can never remove it.
724    *    <li>
725    *       The list MUST NOT include duplicated parameters.
726    *    <li>
727    *       A unique parameter is defined by a combination of a <code>name</code> and <code>location</code>.
728    *    <li>
729    *       The list can use the {@doc SwaggerReferenceObject}
730    *       to link to parameters that are defined at the {@doc SwaggerParameterObject Swagger Object's parameters}.
731    *    <li>
732    *       There can be one <js>"body"</js> parameter at most.
733    * </ul>
734    *
735    * @param value
736    *    The values to add to this property.
737    *    <br>Ignored if <jk>null</jk>.
738    * @return This object (for method chaining).
739    */
740   public Operation addParameters(Collection<ParameterInfo> value) {
741      parameters = addToList(parameters, value);
742      return this;
743   }
744
745   /**
746    * Same as {@link #addParameters(Collection)}.
747    *
748    * @param values
749    *    The values to add to this property.
750    *    <br>Valid types:
751    *    <ul>
752    *       <li>{@link ParameterInfo}
753    *       <li><code>Collection&lt;{@link ParameterInfo}|String&gt;</code>
754    *       <li><code>String</code> - JSON array representation of <code>Collection&lt;{@link ParameterInfo}&gt;</code>
755    *          <h5 class='figure'>Example:</h5>
756    *          <p class='bcode w800'>
757    *    parameters(<js>"[{path:'path',id:'id'}]"</js>);
758    *          </p>
759    *       <li><code>String</code> - JSON object representation of {@link ParameterInfo}
760    *          <h5 class='figure'>Example:</h5>
761    *          <p class='bcode w800'>
762    *    parameters(<js>"{path:'path',id:'id'}"</js>);
763    *          </p>
764    *    </ul>
765    *    <br>Ignored if <jk>null</jk>.
766    * @return This object (for method chaining).
767    */
768   public Operation parameters(Object...values) {
769      parameters = addToList(parameters, values, ParameterInfo.class);
770      return this;
771   }
772
773   /**
774    * Bean property getter:  <property>responses</property>.
775    *
776    * <p>
777    * The list of possible responses as they are returned from executing this operation.
778    *
779    * @return The property value, or <jk>null</jk> if it is not set.
780    */
781   public Map<String,ResponseInfo> getResponses() {
782      return responses;
783   }
784
785
786   /**
787    * Returns the response info with the given status code.
788    *
789    * @param status The HTTP status code.
790    * @return The response info, or <jk>null</jk> if not found.
791    */
792   public ResponseInfo getResponse(Object status) {
793      if (responses != null)
794         return responses.get(String.valueOf(status));
795      return null;
796   }
797
798   /**
799    * Bean property setter:  <property>responses</property>.
800    *
801    * <p>
802    * The list of possible responses as they are returned from executing this operation.
803    *
804    * @param value
805    *    The new value for this property.
806    *    <br>Property value is required.
807    * @return This object (for method chaining).
808    */
809   public Operation setResponses(Map<String,ResponseInfo> value) {
810      responses = newMap(value);
811      return this;
812   }
813
814   /**
815    * Adds one or more values to the <property>responses</property> property.
816    *
817    * <p>
818    * The list of possible responses as they are returned from executing this operation.
819    *
820    * @param values
821    *    The values to add to this property.
822    *    <br>Ignored if <jk>null</jk>.
823    * @return This object (for method chaining).
824    */
825   public Operation addResponses(Map<String,ResponseInfo> values) {
826      responses = addToMap(responses, values);
827      return this;
828   }
829
830   /**
831    * Adds a single value to the <property>responses</property> property.
832    *
833    * @param statusCode The HTTP status code.
834    * @param response The response description.
835    * @return This object (for method chaining).
836    */
837   public Operation response(String statusCode, ResponseInfo response) {
838      return addResponses(Collections.singletonMap(statusCode, response));
839   }
840
841   /**
842    * Same as {@link #addResponses(Map)}.
843    *
844    * @param value
845    *    The new value for this property.
846    *    <br>Valid types:
847    *    <ul>
848    *       <li><code>Map&lt;Integer,{@link ResponseInfo}|String&gt;</code>
849    *       <li><code>String</code> - JSON object representation of <code>Map&lt;Integer,{@link ResponseInfo}&gt;</code>
850    *          <h5 class='figure'>Example:</h5>
851    *          <p class='bcode w800'>
852    *    responses(<js>"{'404':{description:'description',...}}"</js>);
853    *          </p>
854    *    </ul>
855    * @return This object (for method chaining).
856    */
857   public Operation responses(Object...value) {
858      responses = addToMap(responses, value, String.class, ResponseInfo.class);
859      return this;
860   }
861
862   /**
863    * Bean property getter:  <property>schemes</property>.
864    *
865    * <p>
866    * The transfer protocol for the operation.
867    * <br>The value overrides the Swagger Object <code>schemes</code> definition.
868    *
869    * @return The property value, or <jk>null</jk> if it is not set.
870    */
871   public List<String> getSchemes() {
872      return schemes;
873   }
874
875   /**
876    * Bean property setter:  <property>schemes</property>.
877    *
878    * <p>
879    * The transfer protocol for the operation.
880    * <br>The value overrides the Swagger Object <code>schemes</code> definition.
881    *
882    * @param value
883    *    The new value for this property.
884    *    <br>Valid values:
885    *    <ul>
886    *       <li><js>"http"</js>
887    *       <li><js>"https"</js>
888    *       <li><js>"ws"</js>
889    *       <li><js>"wss"</js>
890    *    </ul>
891    *    <br>Can be <jk>null</jk> to unset the property.
892    * @return This object (for method chaining).
893    */
894   public Operation setSchemes(Collection<String> value) {
895      schemes = newList(value);
896      return this;
897   }
898
899   /**
900    * Adds one or more values to the <property>schemes</property> property.
901    *
902    * <p>
903    * The transfer protocol for the operation.
904    * <br>The value overrides the Swagger Object <code>schemes</code> definition.
905    *
906    * @param value
907    *    The values to add to this property.
908    *    <br>Ignored if <jk>null</jk>.
909    * @return This object (for method chaining).
910    */
911   public Operation addSchemes(Collection<String> value) {
912      schemes = addToList(schemes, value);
913      return this;
914   }
915
916   /**
917    * Same as {@link #addSchemes(Collection)}.
918    *
919    * @param values
920    *    The new value for this property.
921    *    <br>Valid types:
922    *    <ul>
923    *       <li><code>Collection&lt;String&gt;</code>
924    *       <li><code>String</code> - JSON array representation of <code>Collection&lt;String&gt;</code>
925    *          <h5 class='figure'>Example:</h5>
926    *          <p class='bcode w800'>
927    *    schemes(<js>"['scheme1','scheme2']"</js>);
928    *          </p>
929    *       <li><code>String</code> - Individual values
930    *          <h5 class='figure'>Example:</h5>
931    *          <p class='bcode w800'>
932    *    schemes(<js>"scheme1</js>, <js>"scheme2"</js>);
933    *          </p>
934    *    </ul>
935    * @return This object (for method chaining).
936    */
937   public Operation schemes(Object...values) {
938      schemes = addToList(schemes, values, String.class);
939      return this;
940   }
941
942   /**
943    * Bean property getter:  <property>deprecated</property>.
944    *
945    * <p>
946    * Declares this operation to be deprecated.
947    *
948    * @return The property value, or <jk>null</jk> if it is not set.
949    */
950   public Boolean getDeprecated() {
951      return deprecated;
952   }
953
954   /**
955    * Bean property getter:  <property>deprecated</property>.
956    *
957    * <p>
958    * Declares this operation to be deprecated.
959    *
960    * @return The property value, or <jk>false</jk> if it is not set.
961    */
962   public boolean isDeprecated() {
963      return deprecated != null && deprecated == true;
964   }
965
966   /**
967    * Bean property setter:  <property>deprecated</property>.
968    *
969    * <p>
970    * Declares this operation to be deprecated.
971    *
972    * @param value T
973    *    The new value for this property.
974    * @return This object (for method chaining).
975    */
976   public Operation setDeprecated(Boolean value) {
977      deprecated = value;
978      return this;
979   }
980
981   /**
982    * Same as {@link #setDeprecated(Boolean)}.
983    *
984    * @param value
985    *    The new value for this property.
986    *    <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>.
987    *    <br>Can be <jk>null</jk> to unset the property.
988    * @return This object (for method chaining).
989    */
990   public Operation deprecated(Object value) {
991      return setDeprecated(toBoolean(value));
992   }
993
994   /**
995    * Bean property getter:  <property>security</property>.
996    *
997    * <p>
998    * A declaration of which security schemes are applied for this operation.
999    * <br>The list of values describes alternative security schemes that can be used (that is, there is a logical OR
1000    * between the security requirements).
1001    *
1002    * <p>
1003    * This definition overrides any declared top-level security.
1004    * <br>To remove a top-level <code>security</code> declaration, an empty array can be used.
1005    *
1006    * @return The property value, or <jk>null</jk> if it is not set.
1007    */
1008   public List<Map<String,List<String>>> getSecurity() {
1009      return security;
1010   }
1011
1012   /**
1013    * Bean property setter:  <property>security</property>.
1014    *
1015    * <p>
1016    * A declaration of which security schemes are applied for this operation.
1017    * <br>The list of values describes alternative security schemes that can be used (that is, there is a logical OR
1018    * between the security requirements).
1019    *
1020    * <p>
1021    * This definition overrides any declared top-level security.
1022    * <br>To remove a top-level <code>security</code> declaration, an empty array can be used.
1023    *
1024    * @param value
1025    *    The new value for this property.
1026    *    <br>Can be <jk>null</jk> to unset the property.
1027    * @return This object (for method chaining).
1028    */
1029   public Operation setSecurity(Collection<Map<String,List<String>>> value) {
1030      security = newList(value);
1031      return this;
1032   }
1033
1034   /**
1035    * Adds one or more values to the <property>security</property> property.
1036    *
1037    * <p>
1038    * A declaration of which security schemes are applied for this operation.
1039    * <br>The list of values describes alternative security schemes that can be used (that is, there is a logical OR
1040    * between the security requirements).
1041    *
1042    * <p>
1043    * This definition overrides any declared top-level security.
1044    * <br>To remove a top-level <code>security</code> declaration, an empty array can be used.
1045    *
1046    * @param values
1047    *    The values to add to this property.
1048    *    <br>Ignored if <jk>null</jk>.
1049    * The new value for this property.
1050    * @return This object (for method chaining).
1051    */
1052   public Operation addSecurity(Collection<Map<String,List<String>>> values) {
1053      security = addToList(security, values);
1054      return this;
1055   }
1056
1057   /**
1058    * Same as {@link #addSecurity(Collection)}.
1059    *
1060    * @param scheme
1061    *    The scheme name.
1062    * @param alternatives
1063    *    The list of values describes alternative security schemes that can be used (that is, there is a logical OR
1064    *    between the security requirements).
1065    * @return This object (for method chaining).
1066    */
1067   public Operation security(String scheme, String...alternatives) {
1068      Map<String,List<String>> m = new LinkedHashMap<>();
1069      m.put(scheme, Arrays.asList(alternatives));
1070      return addSecurity(Collections.singletonList(m));
1071   }
1072
1073   /**
1074    * Same as {@link #addSecurity(Collection)}.
1075    *
1076    * @param value
1077    *    The new value for this property.
1078    *    <br>Valid types:
1079    *    <ul>
1080    *       <li><code>Map&lt;String,List&lt;String&gt;&gt;</code>
1081    *       <li><code>String</code> - JSON object representation of a <code>Map&lt;String,List&lt;String&gt;&gt;</code>
1082    *       <h5 class='figure'>Example:</h5>
1083    *       <p class='bcode w800'>
1084    *    securities(<js>"{key:['val1','val2']}"</js>);
1085    *       </p>
1086    *    </ul>
1087    * @return This object (for method chaining).
1088    */
1089   @SuppressWarnings({ "unchecked", "rawtypes" })
1090   public Operation securities(Object...value) {
1091      security = addToList((List)security, value, Map.class, String.class, List.class, String.class);
1092      return this;
1093   }
1094
1095   /**
1096    * Returns <jk>true</jk> if the summary property is not null or empty.
1097    *
1098    * @return <jk>true</jk> if the summary property is not null or empty.
1099    */
1100   public boolean hasSummary() {
1101      return isNotEmpty(summary);
1102   }
1103
1104   /**
1105    * Returns <jk>true</jk> if the description property is not null or empty.
1106    *
1107    * @return <jk>true</jk> if the description property is not null or empty.
1108    */
1109   public boolean hasDescription() {
1110      return isNotEmpty(description);
1111   }
1112
1113   /**
1114    * Returns <jk>true</jk> if this operation has the specified tag associated with it.
1115    *
1116    * @param name The tag name.
1117    * @return <jk>true</jk> if this operation has the specified tag associated with it.
1118    */
1119   public boolean hasTag(String name) {
1120      return tags != null && tags.contains(name);
1121   }
1122
1123   /**
1124    * Returns <jk>true</jk> if this operation has no tags associated with it.
1125    *
1126    * @return <jk>true</jk> if this operation has no tags associated with it.
1127    */
1128   public boolean hasNoTags() {
1129      return tags == null || tags.isEmpty();
1130   }
1131
1132   /**
1133    * Returns <jk>true</jk> if this operation has parameters associated with it.
1134    *
1135    * @return <jk>true</jk> if this operation has parameters associated with it.
1136    */
1137   public boolean hasParameters() {
1138      return parameters != null && ! parameters.isEmpty();
1139   }
1140
1141   /**
1142    * Returns <jk>true</jk> if this operation has responses associated with it.
1143    *
1144    * @return <jk>true</jk> if this operation has responses associated with it.
1145    */
1146   public boolean hasResponses() {
1147      return responses != null && ! responses.isEmpty();
1148   }
1149
1150   @Override /* SwaggerElement */
1151   public <T> T get(String property, Class<T> type) {
1152      if (property == null)
1153         return null;
1154      switch (property) {
1155         case "tags": return toType(getTags(), type);
1156         case "summary": return toType(getSummary(), type);
1157         case "description": return toType(getDescription(), type);
1158         case "externalDocs": return toType(getExternalDocs(), type);
1159         case "operationId": return toType(getOperationId(), type);
1160         case "consumes": return toType(getConsumes(), type);
1161         case "produces": return toType(getProduces(), type);
1162         case "parameters": return toType(getParameters(), type);
1163         case "responses": return toType(getResponses(), type);
1164         case "schemes": return toType(getSchemes(), type);
1165         case "deprecated": return toType(getDeprecated(), type);
1166         case "security": return toType(getSecurity(), type);
1167         default: return super.get(property, type);
1168      }
1169   }
1170
1171   @Override /* SwaggerElement */
1172   public Operation set(String property, Object value) {
1173      if (property == null)
1174         return this;
1175      switch (property) {
1176         case "tags": return setTags(null).tags(value);
1177         case "summary": return summary(value);
1178         case "description": return description(value);
1179         case "externalDocs": return externalDocs(value);
1180         case "operationId": return operationId(value);
1181         case "consumes": return setConsumes(null).consumes(value);
1182         case "produces": return setProduces(null).produces(value);
1183         case "parameters": return setParameters(null).parameters(value);
1184         case "responses": return setResponses(null).responses(value);
1185         case "schemes": return setSchemes(null).schemes(value);
1186         case "deprecated": return deprecated(value);
1187         case "security": return setSecurity(null).securities(value);
1188         default:
1189            super.set(property, value);
1190            return this;
1191      }
1192   }
1193
1194   @Override /* SwaggerElement */
1195   public Set<String> keySet() {
1196      ASet<String> s = new ASet<String>()
1197         .appendIf(tags != null, "tags")
1198         .appendIf(summary != null, "summary")
1199         .appendIf(description != null, "description")
1200         .appendIf(externalDocs != null, "externalDocs")
1201         .appendIf(operationId != null, "operationId")
1202         .appendIf(consumes != null, "consumes")
1203         .appendIf(produces != null, "produces")
1204         .appendIf(parameters != null, "parameters")
1205         .appendIf(responses != null, "responses")
1206         .appendIf(schemes != null, "schemes")
1207         .appendIf(deprecated != null, "deprecated")
1208         .appendIf(security != null, "security");
1209      return new MultiSet<>(s, super.keySet());
1210   }
1211}