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.CollectionUtils.*;
020import static org.apache.juneau.commons.utils.Shorts.*;
021import static org.apache.juneau.marshall.internal.ConverterUtils.*;
022
023import java.util.*;
024
025import org.apache.juneau.commons.collections.*;
026
027/**
028 * The ServerVariable Object represents a server variable for server URL template substitution. Server variables can be
029 * used to define different server environments (e.g., development, staging, production) with different base URLs,
030 * ports, or other variable parts of the server URL.
031 *
032 * <h5 class='section'>OpenAPI Specification:</h5>
033 * <p>
034 * The ServerVariable Object is composed of the following fields:
035 * <ul class='spaced-list'>
036 *    <li><c>enum</c> (array of any) - An enumeration of string values to be used if the substitution options are from a limited set
037 *    <li><c>default</c> (string, REQUIRED) - The default value to use for substitution, which SHALL be sent if an alternate value is not supplied
038 *    <li><c>description</c> (string) - An optional description for the server variable. CommonMark syntax MAY be used for rich text representation
039 * </ul>
040 *
041 * <h5 class='section'>Example:</h5>
042 * <p class='bcode'>
043 *    <jc>// Construct using SwaggerBuilder.</jc>
044 *    ServerVariable <jv>x</jv> = <jsm>serverVariable</jsm>()
045 *       .setDefault(<js>"api"</js>)
046 *       .setEnum(<js>"api"</js>, <js>"staging"</js>, <js>"dev"</js>)
047 *       .setDescription(<js>"Environment to use"</js>);
048 *
049 *    <jc>// Serialize using JsonSerializer.</jc>
050 *    String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>x</jv>);
051 *
052 *    <jc>// Or just use toString() which does the same as above.</jc>
053 *    <jv>json</jv> = <jv>x</jv>.toString();
054 * </p>
055 * <p class='bcode'>
056 *    <jc>// Output</jc>
057 *    {
058 *       <js>"default"</js>: <js>"api"</js>,
059 *       <js>"enum"</js>: [<js>"api"</js>, <js>"staging"</js>, <js>"dev"</js>],
060 *       <js>"description"</js>: <js>"Environment to use"</js>
061 *    }
062 * </p>
063 *
064 * <h5 class='section'>See Also:</h5><ul>
065 *    <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>
066 *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/api-host-and-base-path/">OpenAPI API Host and Base Path</a>
067 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
068 * </ul>
069 */
070@SuppressWarnings({
071   "java:S116", // Field name uses trailing underscore (default_) to avoid Java keyword conflict
072   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
073})
074public class ServerVariable extends OpenApiElement {
075
076   private final 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      this.enum_.addAll(cp(copyFrom.enum_));
094      this.default_ = copyFrom.default_;
095      this.description = copyFrom.description;
096   }
097
098   /**
099    * Adds one or more values to the <property>enum</property> property.
100    *
101    * @param values
102    *    The values to add to this property.
103    *    <br>Valid types:
104    *    <ul>
105    *       <li><code>Object</code>
106    *       <li><code>Collection&lt;Object&gt;</code>
107    *       <li><code>String</code> - JSON array representation of <code>Collection&lt;Object&gt;</code>
108    *          <h5 class='figure'>Example:</h5>
109    *          <p class='bcode'>
110    *    enum_(<js>"['foo','bar']"</js>);
111    *          </p>
112    *       <li><code>String</code> - Individual values
113    *          <h5 class='figure'>Example:</h5>
114    *          <p class='bcode'>
115    *    enum_(<js>"foo"</js>, <js>"bar"</js>);
116    *          </p>
117    *    </ul>
118    *    <br>Ignored if <jk>null</jk>.
119    * @return This object
120    */
121   public ServerVariable addEnum(Object...values) {
122      addAllNn(enum_, values);
123      return this;
124   }
125
126   /**
127    * Make a deep copy of this object.
128    * @return A deep copy of this object.
129    */
130   public ServerVariable copy() {
131      return new ServerVariable(this);
132   }
133
134   @Override /* Overridden from OpenApiElement */
135   public <T> T get(String property, Class<T> type) {
136      reqnn("property", property);
137      return switch (property) {
138         case "enum" -> toType(getEnum(), type);
139         case "default" -> toType(getDefault(), type);
140         case "description" -> toType(getDescription(), type);
141         default -> super.get(property, type);
142      };
143   }
144
145   /**
146    * Bean property getter:  <property>default</property>.
147    *
148    * <p>
149    * Declares the value of the item that the server will use if none is provided.
150    *
151    * <h5 class='section'>Notes:</h5>
152    * <ul class='spaced-list'>
153    *    <li>
154    *       <js>"default"</js> has no meaning for required items.
155    *    <li>
156    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
157    * </ul>
158    *
159    * @return The property value, or <jk>null</jk> if it is not set.
160    */
161   public String getDefault() { return default_; }
162
163   /**
164    * Bean property getter:  <property>description</property>.
165    *
166    * <p>
167    * An optional description for the server variable.
168    *
169    * @return The property value, or <jk>null</jk> if it is not set.
170    */
171   public String getDescription() { return description; }
172
173   /**
174    * Bean property getter:  <property>enum</property>.
175    *
176    * @return The property value, or <jk>null</jk> if it is not set.
177    */
178   public List<Object> getEnum() { return nie(enum_); }
179
180   @Override /* Overridden from OpenApiElement */
181   public Set<String> keySet() {
182      // @formatter:off
183      var s = stb(String.class)
184         .addIf(nn(default_), "default")
185         .addIf(nn(description), "description")
186         .addIf(ine(enum_), "enum")
187         .build();
188      // @formatter:on
189      return new MultiSet<>(s, super.keySet());
190   }
191
192   @Override /* Overridden from OpenApiElement */
193   public ServerVariable set(String property, Object value) {
194      reqnn("property", property);
195      return switch (property) {
196         case "default" -> setDefault(s(value));
197         case "description" -> setDescription(s(value));
198         case "enum" -> setEnum(lb(Object.class).addAny(value).sparse().build());
199         default -> {
200            super.set(property, value);
201            yield this;
202         }
203      };
204   }
205
206   /**
207    * Bean property setter:  <property>default</property>.
208    *
209    * <p>
210    * Declares the value of the item that the server will use if none is provided.
211    *
212    * <h5 class='section'>Notes:</h5>
213    * <ul class='spaced-list'>
214    *    <li>
215    *       <js>"default"</js> has no meaning for required items.
216    *    <li>
217    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
218    * </ul>
219    *
220    * @param value
221    *    The new value for this property.
222    *    <br>Can be <jk>null</jk> to unset the property.
223    * @return This object
224    */
225   public ServerVariable setDefault(String value) {
226      default_ = value;
227      return this;
228   }
229
230   /**
231    * Bean property setter:  <property>description</property>.
232    *
233    * <p>
234    * An optional description for the server variable.
235    *
236    * @param value
237    *    The new value for this property.
238    *    <br>Can be <jk>null</jk> to unset the property.
239    * @return This object
240    */
241   public ServerVariable setDescription(String value) {
242      description = value;
243      return this;
244   }
245
246   /**
247    * Bean property setter:  <property>enum</property>.
248    *
249    * @param value
250    *    The new value for this property.
251    *    <br>Can be <jk>null</jk> to unset the property.
252    * @return This object
253    */
254   public ServerVariable setEnum(Collection<Object> value) {
255      enum_.clear();
256      if (nn(value))
257         enum_.addAll(value);
258      return this;
259   }
260
261   @Override /* Overridden from OpenApiElement */
262   public ServerVariable strict(Object value) {
263      super.strict(value);
264      return this;
265   }
266
267   @Override /* Overridden from OpenApiElement */
268   protected ServerVariable strict() {
269      super.strict();
270      return this;
271   }
272}