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