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