1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.juneau.bean.openapi3;
18
19 import static org.apache.juneau.commons.utils.AssertionUtils.*;
20 import static org.apache.juneau.commons.utils.CollectionUtils.*;
21 import static org.apache.juneau.commons.utils.StringUtils.*;
22 import static org.apache.juneau.commons.utils.Utils.*;
23 import static org.apache.juneau.internal.ConverterUtils.*;
24
25 import java.net.*;
26 import java.util.*;
27
28 import org.apache.juneau.*;
29 import org.apache.juneau.commons.collections.*;
30
31 /**
32 * An object representing a Server.
33 *
34 * <p>
35 * The Server Object represents a server that provides connectivity information to a target server. This can be used
36 * to specify different servers for different environments (e.g., development, staging, production) or to provide
37 * server-specific configuration such as variables for templating.
38 *
39 * <h5 class='section'>OpenAPI Specification:</h5>
40 * <p>
41 * The Server Object is composed of the following fields:
42 * <ul class='spaced-list'>
43 * <li><c>url</c> (string, REQUIRED) - A URL to the target host. This URL supports Server Variables and may be relative
44 * <li><c>description</c> (string) - An optional string describing the host designated by the URL (CommonMark syntax may be used)
45 * <li><c>variables</c> (map of {@link ServerVariable}) - A map between a variable name and its value
46 * </ul>
47 *
48 * <h5 class='section'>Example:</h5>
49 * <p class='bjava'>
50 * <jc>// Create a server with variables</jc>
51 * Server <jv>server</jv> = <jk>new</jk> Server()
52 * .setUrl(<js>"https://{username}.gigantic-server.com:{port}/{basePath}"</js>)
53 * .setDescription(<js>"The production API server"</js>)
54 * .setVariables(
55 * JsonMap.<jsm>of</jsm>(
56 * <js>"username"</js>, <jk>new</jk> ServerVariable()
57 * .setDefault(<js>"demo"</js>)
58 * .setDescription(<js>"this value is assigned by the service provider"</js>),
59 * <js>"port"</js>, <jk>new</jk> ServerVariable()
60 * .setDefault(<js>"8443"</js>)
61 * .setEnum(<js>"8443"</js>, <js>"443"</js>),
62 * <js>"basePath"</js>, <jk>new</jk> ServerVariable()
63 * .setDefault(<js>"v2"</js>)
64 * )
65 * );
66 * </p>
67 *
68 * <h5 class='section'>See Also:</h5><ul>
69 * <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#server-object">OpenAPI Specification > Server Object</a>
70 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/api-host-and-base-path/">OpenAPI API Host and Base Path</a>
71 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
72 * </ul>
73 */
74 public class Server extends OpenApiElement {
75 private URI url;
76 private String description;
77 private Map<String,ServerVariable> variables = map();
78
79 /**
80 * Default constructor.
81 */
82 public Server() {}
83
84 /**
85 * Copy constructor.
86 *
87 * @param copyFrom The object to copy.
88 */
89 public Server(Server copyFrom) {
90 super(copyFrom);
91
92 this.url = copyFrom.url;
93 this.description = copyFrom.description;
94 if (nn(copyFrom.variables))
95 variables.putAll(copyOf(copyFrom.variables, ServerVariable::copy));
96 }
97
98 /**
99 * 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 }