001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.bean.openapi3;
018
019import static org.apache.juneau.common.utils.Utils.*;
020import static org.apache.juneau.internal.CollectionUtils.*;
021import static org.apache.juneau.internal.ConverterUtils.*;
022
023import java.util.*;
024
025import org.apache.juneau.common.utils.*;
026import org.apache.juneau.internal.*;
027
028/**
029 * TODO
030 *
031 * <p>
032 * The ServerVariable Object represents a server variable for server URL template substitution. Server variables can be 
033 * used to define different server environments (e.g., development, staging, production) with different base URLs, 
034 * ports, or other variable parts of the server URL.
035 *
036 * <h5 class='section'>OpenAPI Specification:</h5>
037 * <p>
038 * The ServerVariable Object is composed of the following fields:
039 * <ul class='spaced-list'>
040 *    <li><c>enum</c> (array of any) - An enumeration of string values to be used if the substitution options are from a limited set
041 *    <li><c>default</c> (string, REQUIRED) - The default value to use for substitution, which SHALL be sent if an alternate value is not supplied
042 *    <li><c>description</c> (string) - An optional description for the server variable. CommonMark syntax MAY be used for rich text representation
043 * </ul>
044 *
045 * <h5 class='section'>Example:</h5>
046 * <p class='bcode'>
047 *    <jc>// Construct using SwaggerBuilder.</jc>
048 *    ServerVariable <jv>x</jv> = <jsm>serverVariable</jsm>()
049 *       .setDefault(<js>"api"</js>)
050 *       .setEnum(<js>"api"</js>, <js>"staging"</js>, <js>"dev"</js>)
051 *       .setDescription(<js>"Environment to use"</js>);
052 *
053 *    <jc>// Serialize using JsonSerializer.</jc>
054 *    String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>x</jv>);
055 *
056 *    <jc>// Or just use toString() which does the same as above.</jc>
057 *    <jv>json</jv> = <jv>x</jv>.toString();
058 * </p>
059 * <p class='bcode'>
060 *    <jc>// Output</jc>
061 *    {
062 *       <js>"default"</js>: <js>"api"</js>,
063 *       <js>"enum"</js>: [<js>"api"</js>, <js>"staging"</js>, <js>"dev"</js>],
064 *       <js>"description"</js>: <js>"Environment to use"</js>
065 *    }
066 * </p>
067 *
068 * <h5 class='section'>See Also:</h5><ul>
069 *    <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#server-variable-object">OpenAPI Specification &gt; Server Variable Object</a>
070 *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/api-host-and-base-path/">OpenAPI API Host and Base Path</a>
071 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
072 * </ul>
073 */
074public class ServerVariable extends OpenApiElement {
075
076   private List<Object> _enum;  // NOSONAR - Intentional naming.
077   private String _default;  // NOSONAR - Intentional naming.
078   private String description;
079
080   /**
081    * Default constructor.
082    */
083   public ServerVariable() {}
084
085   /**
086    * Copy constructor.
087    *
088    * @param copyFrom The object to copy.
089    */
090   public ServerVariable(ServerVariable copyFrom) {
091      super(copyFrom);
092
093      this._enum = copyOf(copyFrom._enum);
094      this._default = copyFrom._default;
095      this.description = copyFrom.description;
096   }
097
098   /**
099    * Make a deep copy of this object.
100    * @return A deep copy of this object.
101    */
102   public ServerVariable copy() {
103      return new ServerVariable(this);
104   }
105
106   @Override /* Overridden from OpenApiElement */
107   protected ServerVariable strict() {
108      super.strict();
109      return this;
110   }
111
112   @Override /* Overridden from OpenApiElement */
113   public ServerVariable strict(Object value) {
114      super.strict(value);
115      return this;
116   }
117
118   /**
119    * Bean property getter:  <property>enum</property>.
120    *
121    * @return The property value, or <jk>null</jk> if it is not set.
122    */
123   public List<Object> getEnum() {
124      return _enum;
125   }
126
127   /**
128    * Bean property setter:  <property>enum</property>.
129    *
130    * @param value
131    *    The new value for this property.
132    *    <br>Can be <jk>null</jk> to unset the property.
133    * @return This object
134    */
135   public ServerVariable setEnum(Collection<Object> value) {
136      _enum = listFrom(value);
137      return this;
138   }
139
140   /**
141    * Adds one or more values to the <property>enum</property> property.
142    *
143    * @param values
144    *    The values to add to this property.
145    *    <br>Valid types:
146    *    <ul>
147    *       <li><code>Object</code>
148    *       <li><code>Collection&lt;Object&gt;</code>
149    *       <li><code>String</code> - JSON array representation of <code>Collection&lt;Object&gt;</code>
150    *          <h5 class='figure'>Example:</h5>
151    *          <p class='bcode'>
152    *    _enum(<js>"['foo','bar']"</js>);
153    *          </p>
154    *       <li><code>String</code> - Individual values
155    *          <h5 class='figure'>Example:</h5>
156    *          <p class='bcode'>
157    *    _enum(<js>"foo"</js>, <js>"bar"</js>);
158    *          </p>
159    *    </ul>
160    *    <br>Ignored if <jk>null</jk>.
161    * @return This object
162    */
163   public ServerVariable addEnum(Object...values) {
164      _enum = listBuilder(_enum).elementType(Object.class).sparse().addAny(values).build();
165      return this;
166   }
167
168   /**
169    * Bean property getter:  <property>default</property>.
170    *
171    * <p>
172    * Declares the value of the item that the server will use if none is provided.
173    *
174    * <h5 class='section'>Notes:</h5>
175    * <ul class='spaced-list'>
176    *    <li>
177    *       <js>"default"</js> has no meaning for required items.
178    *    <li>
179    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
180    * </ul>
181    *
182    * @return The property value, or <jk>null</jk> if it is not set.
183    */
184   public String getDefault() {
185      return _default;
186   }
187
188   /**
189    * Bean property setter:  <property>default</property>.
190    *
191    * <p>
192    * Declares the value of the item that the server will use if none is provided.
193    *
194    * <h5 class='section'>Notes:</h5>
195    * <ul class='spaced-list'>
196    *    <li>
197    *       <js>"default"</js> has no meaning for required items.
198    *    <li>
199    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
200    * </ul>
201    *
202    * @param value
203    *    The new value for this property.
204    *    <br>Can be <jk>null</jk> to unset the property.
205    * @return This object
206    */
207   public ServerVariable setDefault(String value) {
208      _default = value;
209      return this;
210   }
211
212   /**
213    * Bean property getter:  <property>description</property>.
214    *
215    * <p>
216    * Declares the value of the item that the server will use if none is provided.
217    *
218    * <h5 class='section'>Notes:</h5>
219    * <ul class='spaced-list'>
220    *    <li>
221    *       <js>"description"</js> has no meaning for required items.
222    *    <li>
223    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
224    * </ul>
225    *
226    * @return The property value, or <jk>null</jk> if it is not set.
227    */
228   public String getDescription() {
229      return description;
230   }
231
232   /**
233    * Bean property setter:  <property>description</property>.
234    *
235    * <p>
236    * Declares the value of the item that the server will use if none is provided.
237    *
238    * <h5 class='section'>Notes:</h5>
239    * <ul class='spaced-list'>
240    *    <li>
241    *       <js>"description"</js> has no meaning for required items.
242    *    <li>
243    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
244    * </ul>
245    *
246    * @param value
247    *    The new value for this property.
248    *    <br>Can be <jk>null</jk> to unset the property.
249    * @return This object
250    */
251   public ServerVariable setDescription(String value) {
252      description = value;
253      return this;
254   }
255
256   @Override /* Overridden from OpenApiElement */
257   public <T> T get(String property, Class<T> type) {
258      assertArgNotNull("property", property);
259      return switch (property) {
260         case "enum" -> toType(getEnum(), type);
261         case "default" -> toType(getDefault(), type);
262         case "description" -> toType(getDescription(), type);
263         default -> super.get(property, type);
264      };
265   }
266
267   @Override /* Overridden from OpenApiElement */
268   public ServerVariable set(String property, Object value) {
269      assertArgNotNull("property", property);
270      return switch (property) {
271         case "default" -> setDefault(Utils.s(value));
272         case "description" -> setDescription(Utils.s(value));
273         case "enum" -> setEnum(listBuilder(Object.class).sparse().addAny(value).build());
274         default -> {
275            super.set(property, value);
276            yield this;
277         }
278      };
279   }
280
281   @Override /* Overridden from OpenApiElement */
282   public Set<String> keySet() {
283      var s = setBuilder(String.class)
284         .addIf(_default != null,"default" )
285         .addIf(description != null, "description")
286         .addIf(_enum != null, "enum")
287         .build();
288      return new MultiSet<>(s, super.keySet());
289   }
290}