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.commons.utils.StringUtils.*;
022import static org.apache.juneau.marshall.internal.ConverterUtils.*;
023
024import java.net.*;
025import java.util.*;
026
027import org.apache.juneau.commons.collections.*;
028import org.apache.juneau.marshall.*;
029
030/**
031 * An object representing a Server.
032 *
033 * <p>
034 * The Server Object represents a server that provides connectivity information to a target server. This can be used
035 * to specify different servers for different environments (e.g., development, staging, production) or to provide
036 * server-specific configuration such as variables for templating.
037 *
038 * <h5 class='section'>OpenAPI Specification:</h5>
039 * <p>
040 * The Server Object is composed of the following fields:
041 * <ul class='spaced-list'>
042 *    <li><c>url</c> (string, REQUIRED) - A URL to the target host. This URL supports Server Variables and may be relative
043 *    <li><c>description</c> (string) - An optional string describing the host designated by the URL (CommonMark syntax may be used)
044 *    <li><c>variables</c> (map of {@link ServerVariable}) - A map between a variable name and its value
045 * </ul>
046 *
047 * <h5 class='section'>Example:</h5>
048 * <p class='bjava'>
049 *    <jc>// Create a server with variables</jc>
050 *    Server <jv>server</jv> = <jk>new</jk> Server()
051 *       .setUrl(<js>"https://{username}.gigantic-server.com:{port}/{basePath}"</js>)
052 *       .setDescription(<js>"The production API server"</js>)
053 *       .setVariables(
054 *          JsonMap.<jsm>of</jsm>(
055 *             <js>"username"</js>, <jk>new</jk> ServerVariable()
056 *                .setDefault(<js>"demo"</js>)
057 *                .setDescription(<js>"this value is assigned by the service provider"</js>),
058 *             <js>"port"</js>, <jk>new</jk> ServerVariable()
059 *                .setDefault(<js>"8443"</js>)
060 *                .setEnum(<js>"8443"</js>, <js>"443"</js>),
061 *             <js>"basePath"</js>, <jk>new</jk> ServerVariable()
062 *                .setDefault(<js>"v2"</js>)
063 *          )
064 *       );
065 * </p>
066 *
067 * <h5 class='section'>See Also:</h5><ul>
068 *    <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#server-object">OpenAPI Specification &gt; Server Object</a>
069 *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/api-host-and-base-path/">OpenAPI API Host and Base Path</a>
070 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
071 * </ul>
072 */
073@SuppressWarnings({
074   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
075})
076public class Server extends OpenApiElement {
077
078   private URI url;
079   private String description;
080   private final Map<String,ServerVariable> variables = map();
081
082   /**
083    * Default constructor.
084    */
085   public Server() {}
086
087   /**
088    * Copy constructor.
089    *
090    * @param copyFrom The object to copy.
091    */
092   public Server(Server copyFrom) {
093      super(copyFrom);
094
095      this.url = copyFrom.url;
096      this.description = copyFrom.description;
097      variables.putAll(cp(copyFrom.variables, ServerVariable::copy));
098   }
099
100   /**
101    * Adds one or more values to the <property>variables</property> property.
102    *
103    * @param key The mapping key.  Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown.
104    * @param value
105    *    The values to add to this property.
106    *    <br>Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown.
107    *    <br>Ignored if <jk>null</jk>.
108    * @return This object
109    */
110   public Server addVariable(String key, ServerVariable value) {
111      reqnn("key", key);
112      reqnn("value", value);
113      variables.put(key, value);
114      return this;
115   }
116
117   /**
118    * Make a deep copy of this object.
119    *
120    * @return A deep copy of this object.
121    */
122   public Server copy() {
123      return new Server(this);
124   }
125
126   @Override /* Overridden from OpenApiElement */
127   public <T> T get(String property, Class<T> type) {
128      reqnn("property", property);
129      return switch (property) {
130         case "url" -> toType(getUrl(), type);
131         case "description" -> toType(getDescription(), type);
132         case "variables" -> toType(getVariables(), type);
133         default -> super.get(property, type);
134      };
135   }
136
137   /**
138    * Bean property getter:  <property>description</property>.
139    *
140    * @return The property value, or <jk>null</jk> if it is not set.
141    */
142   public String getDescription() { return description; }
143
144   /**
145    * Bean property getter:  <property>url</property>.
146    *
147    * <p>
148    * A URL to the target host.
149    *
150    * @return The property value, or <jk>null</jk> if it is not set.
151    */
152   public URI getUrl() { return url; }
153
154   /**
155    * Bean property getter:  <property>variables</property>.
156    *
157    * @return The property value, or <jk>null</jk> if it is not set.
158    */
159   public Map<String,ServerVariable> getVariables() { return nie(variables); }
160
161   @Override /* Overridden from OpenApiElement */
162   public Set<String> keySet() {
163      // @formatter:off
164      var s = stb(String.class)
165         .addIf(nn(description), "description")
166         .addIf(nn(url), "url")
167         .addIf(ine(variables), "variables")
168         .build();
169      // @formatter:on
170      return new MultiSet<>(s, super.keySet());
171   }
172
173   @Override /* Overridden from OpenApiElement */
174   public Server set(String property, Object value) {
175      reqnn("property", property);
176      return switch (property) {
177         case "description" -> setDescription(s(value));
178         case "url" -> setUrl(toUri(value));
179         case "variables" -> setVariables(toMapBuilder(value, String.class, ServerVariable.class).sparse().build());
180         default -> {
181            super.set(property, value);
182            yield this;
183         }
184      };
185   }
186
187   /**
188    * Bean property setter:  <property>description</property>.
189    *
190    * @param value
191    *    The new value for this property.
192    *    <br>Can be <jk>null</jk> to unset the property.
193    * @return This object
194    */
195   public Server setDescription(String value) {
196      description = value;
197      return this;
198   }
199
200   /**
201    * Bean property setter:  <property>url</property>.
202    *
203    * <p>
204    * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
205    * <br>Strings must be valid URIs.
206    *
207    * <p>
208    * URIs defined by {@link UriResolver} can be used for values.
209    *
210    * @param value
211    *    The new value for this property.
212    *    <br>Can be <jk>null</jk> to unset the property.
213    * @return This object
214    */
215   public Server setUrl(URI value) {
216      url = value;
217      return this;
218   }
219
220   /**
221    * Bean property setter:  <property>variables</property>.
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
227    */
228   public Server setVariables(Map<String,ServerVariable> value) {
229      variables.clear();
230      if (nn(value))
231         variables.putAll(value);
232      return this;
233   }
234
235   @Override /* Overridden from OpenApiElement */
236   public Server strict(Object value) {
237      super.strict(value);
238      return this;
239   }
240
241   @Override /* Overridden from OpenApiElement */
242   protected Server strict() {
243      super.strict();
244      return this;
245   }
246}