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.StringUtils.*;
020import static org.apache.juneau.common.utils.Utils.*;
021import static org.apache.juneau.internal.CollectionUtils.*;
022import static org.apache.juneau.internal.ConverterUtils.*;
023
024import java.net.*;
025import java.util.*;
026
027import org.apache.juneau.*;
028import org.apache.juneau.common.utils.*;
029import org.apache.juneau.internal.*;
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;
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      this.variables = copyOf(copyFrom.variables, ServerVariable::copy);
095   }
096
097   /**
098    * Make a deep copy of this object.
099    *
100    * @return A deep copy of this object.
101    */
102   public Server copy() {
103      return new Server(this);
104   }
105
106   @Override /* Overridden from OpenApiElement */
107   protected Server strict() {
108      super.strict();
109      return this;
110   }
111
112   @Override /* Overridden from OpenApiElement */
113   public Server strict(Object value) {
114      super.strict(value);
115      return this;
116   }
117
118   /**
119    * Bean property getter:  <property>url</property>.
120    *
121    * <p>
122    * The URL pointing to the contact information.
123    *
124    * @return The property value, or <jk>null</jk> if it is not set.
125    */
126   public URI getUrl() {
127      return url;
128   }
129
130   /**
131    * Bean property setter:  <property>url</property>.
132    *
133    * <p>
134    * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
135    * <br>Strings must be valid URIs.
136    *
137    * <p>
138    * URIs defined by {@link UriResolver} can be used for values.
139    *
140    * @param value
141    *    The new value for this property.
142    *    <br>Can be <jk>null</jk> to unset the property.
143    * @return This object
144    */
145   public Server setUrl(URI value) {
146      url = value;
147      return this;
148   }
149
150   /**
151    * Bean property getter:  <property>description</property>.
152    *
153    * @return The property value, or <jk>null</jk> if it is not set.
154    */
155   public String getDescription() {
156      return description;
157   }
158
159   /**
160    * Bean property setter:  <property>description</property>.
161    *
162    * @param value
163    *    The new value for this property.
164    *    <br>Can be <jk>null</jk> to unset the property.
165    * @return This object
166    */
167   public Server setDescription(String value) {
168      description = value;
169      return this;
170   }
171
172   /**
173    * Bean property getter:  <property>variables</property>.
174    *
175    * @return The property value, or <jk>null</jk> if it is not set.
176    */
177   public Map<String, ServerVariable> getVariables() {
178      return variables;
179   }
180
181   /**
182    * Bean property setter:  <property>variables</property>.
183    *
184    * @param value
185    *    The new value for this property.
186    *    <br>Can be <jk>null</jk> to unset the property.
187    * @return This object
188    */
189   public Server setVariables(Map<String, ServerVariable> value) {
190      variables = copyOf(value);
191      return this;
192   }
193
194   /**
195    * Adds one or more values to the <property>variables</property> property.
196    *
197    * @param key The mapping key.  Must not be <jk>null</jk>.
198    * @param value
199    *    The values to add to this property.
200    *    <br>Must not be <jk>null</jk>.
201    *    <br>Ignored if <jk>null</jk>.
202    * @return This object
203    */
204   public Server addVariable(String key, ServerVariable value) {
205      assertArgNotNull("key", key);
206      assertArgNotNull("value", value);
207      variables = mapBuilder(variables).sparse().add(key, value).build();
208      return this;
209   }
210
211   @Override /* Overridden from OpenApiElement */
212   public <T> T get(String property, Class<T> type) {
213      assertArgNotNull("property", property);
214      return switch (property) {
215         case "url" -> toType(getUrl(), type);
216         case "description" -> toType(getDescription(), type);
217         case "variables" -> toType(getVariables(), type);
218         default -> super.get(property, type);
219      };
220   }
221
222   @Override /* Overridden from OpenApiElement */
223   public Server set(String property, Object value) {
224      assertArgNotNull("property", property);
225      return switch (property) {
226         case "description" -> setDescription(Utils.s(value));
227         case "url" -> setUrl(toURI(value));
228         case "variables" -> setVariables(mapBuilder(String.class,ServerVariable.class).sparse().addAny(value).build());
229         default -> {
230            super.set(property, value);
231            yield this;
232         }
233      };
234   }
235
236   @Override /* Overridden from OpenApiElement */
237   public Set<String> keySet() {
238      var s = setBuilder(String.class)
239         .addIf(description != null, "description")
240         .addIf(url != null, "url")
241         .addIf(variables != null, "variables")
242         .build();
243      return new MultiSet<>(s, super.keySet());
244   }
245}