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.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.Utils.*;
022import static org.apache.juneau.internal.ConverterUtils.*;
023
024import java.util.*;
025
026import org.apache.juneau.commons.collections.*;
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_ = list();
077   private String default_;
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      if (nn(copyFrom.enum_))
094         this.enum_.addAll(copyOf(copyFrom.enum_));
095      this.default_ = copyFrom.default_;
096      this.description = copyFrom.description;
097   }
098
099   /**
100    * Adds one or more values to the <property>enum</property> property.
101    *
102    * @param values
103    *    The values to add to this property.
104    *    <br>Valid types:
105    *    <ul>
106    *       <li><code>Object</code>
107    *       <li><code>Collection&lt;Object&gt;</code>
108    *       <li><code>String</code> - JSON array representation of <code>Collection&lt;Object&gt;</code>
109    *          <h5 class='figure'>Example:</h5>
110    *          <p class='bcode'>
111    *    enum_(<js>"['foo','bar']"</js>);
112    *          </p>
113    *       <li><code>String</code> - Individual values
114    *          <h5 class='figure'>Example:</h5>
115    *          <p class='bcode'>
116    *    enum_(<js>"foo"</js>, <js>"bar"</js>);
117    *          </p>
118    *    </ul>
119    *    <br>Ignored if <jk>null</jk>.
120    * @return This object
121    */
122   public ServerVariable addEnum(Object...values) {
123      if (nn(values))
124         for (var v : values)
125            if (nn(v))
126               enum_.add(v);
127      return this;
128   }
129
130   /**
131    * Make a deep copy of this object.
132    * @return A deep copy of this object.
133    */
134   public ServerVariable copy() {
135      return new ServerVariable(this);
136   }
137
138   @Override /* Overridden from OpenApiElement */
139   public <T> T get(String property, Class<T> type) {
140      assertArgNotNull("property", property);
141      return switch (property) {
142         case "enum" -> toType(getEnum(), type);
143         case "default" -> toType(getDefault(), type);
144         case "description" -> toType(getDescription(), type);
145         default -> super.get(property, type);
146      };
147   }
148
149   /**
150    * Bean property getter:  <property>default</property>.
151    *
152    * <p>
153    * Declares the value of the item that the server will use if none is provided.
154    *
155    * <h5 class='section'>Notes:</h5>
156    * <ul class='spaced-list'>
157    *    <li>
158    *       <js>"default"</js> has no meaning for required items.
159    *    <li>
160    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
161    * </ul>
162    *
163    * @return The property value, or <jk>null</jk> if it is not set.
164    */
165   public String getDefault() { return default_; }
166
167   /**
168    * Bean property getter:  <property>description</property>.
169    *
170    * <p>
171    * Declares the value of the item that the server will use if none is provided.
172    *
173    * <h5 class='section'>Notes:</h5>
174    * <ul class='spaced-list'>
175    *    <li>
176    *       <js>"description"</js> has no meaning for required items.
177    *    <li>
178    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
179    * </ul>
180    *
181    * @return The property value, or <jk>null</jk> if it is not set.
182    */
183   public String getDescription() { return description; }
184
185   /**
186    * Bean property getter:  <property>enum</property>.
187    *
188    * @return The property value, or <jk>null</jk> if it is not set.
189    */
190   public List<Object> getEnum() { return nullIfEmpty(enum_); }
191
192   @Override /* Overridden from OpenApiElement */
193   public Set<String> keySet() {
194      // @formatter:off
195      var s = setb(String.class)
196         .addIf(nn(default_),"default" )
197         .addIf(nn(description), "description")
198         .addIf(ne(enum_), "enum")
199         .build();
200      // @formatter:on
201      return new MultiSet<>(s, super.keySet());
202   }
203
204   @Override /* Overridden from OpenApiElement */
205   public ServerVariable set(String property, Object value) {
206      assertArgNotNull("property", property);
207      return switch (property) {
208         case "default" -> setDefault(s(value));
209         case "description" -> setDescription(s(value));
210         case "enum" -> setEnum(listb(Object.class).addAny(value).sparse().build());
211         default -> {
212            super.set(property, value);
213            yield this;
214         }
215      };
216   }
217
218   /**
219    * Bean property setter:  <property>default</property>.
220    *
221    * <p>
222    * Declares the value of the item that the server will use if none is provided.
223    *
224    * <h5 class='section'>Notes:</h5>
225    * <ul class='spaced-list'>
226    *    <li>
227    *       <js>"default"</js> has no meaning for required items.
228    *    <li>
229    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
230    * </ul>
231    *
232    * @param value
233    *    The new value for this property.
234    *    <br>Can be <jk>null</jk> to unset the property.
235    * @return This object
236    */
237   public ServerVariable setDefault(String value) {
238      default_ = value;
239      return this;
240   }
241
242   /**
243    * Bean property setter:  <property>description</property>.
244    *
245    * <p>
246    * Declares the value of the item that the server will use if none is provided.
247    *
248    * <h5 class='section'>Notes:</h5>
249    * <ul class='spaced-list'>
250    *    <li>
251    *       <js>"description"</js> has no meaning for required items.
252    *    <li>
253    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
254    * </ul>
255    *
256    * @param value
257    *    The new value for this property.
258    *    <br>Can be <jk>null</jk> to unset the property.
259    * @return This object
260    */
261   public ServerVariable setDescription(String value) {
262      description = value;
263      return this;
264   }
265
266   /**
267    * Bean property setter:  <property>enum</property>.
268    *
269    * @param value
270    *    The new value for this property.
271    *    <br>Can be <jk>null</jk> to unset the property.
272    * @return This object
273    */
274   public ServerVariable setEnum(Collection<Object> value) {
275      enum_.clear();
276      if (nn(value))
277         enum_.addAll(value);
278      return this;
279   }
280
281   @Override /* Overridden from OpenApiElement */
282   public ServerVariable strict(Object value) {
283      super.strict(value);
284      return this;
285   }
286
287   @Override /* Overridden from OpenApiElement */
288   protected ServerVariable strict() {
289      super.strict();
290      return this;
291   }
292}