View Javadoc
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.Utils.*;
22  import static org.apache.juneau.internal.ConverterUtils.*;
23  
24  import java.util.*;
25  
26  import org.apache.juneau.commons.collections.*;
27  
28  /**
29   * The Link object represents a possible design-time link for a response.
30   *
31   * <p>
32   * The Link Object represents a possible design-time link for a response. The presence of a link does not guarantee
33   * the caller's ability to successfully invoke it, rather it provides a known relationship and traversal mechanism
34   * between responses and other operations.
35   *
36   * <h5 class='section'>OpenAPI Specification:</h5>
37   * <p>
38   * The Link Object is composed of the following fields:
39   * <ul class='spaced-list'>
40   * 	<li><c>operationRef</c> (string) - A relative or absolute reference to an OAS operation (mutually exclusive with <c>operationId</c>)
41   * 	<li><c>operationId</c> (string) - The name of an existing, resolvable OAS operation (mutually exclusive with <c>operationRef</c>)
42   * 	<li><c>parameters</c> (map of any) - A map representing parameters to pass to an operation as specified with <c>operationId</c> or identified via <c>operationRef</c>
43   * 	<li><c>requestBody</c> (any) - A literal value or expression to use as a request body when calling the target operation
44   * 	<li><c>description</c> (string) - A description of the link (CommonMark syntax may be used)
45   * 	<li><c>server</c> ({@link Server}) - A server object to be used by the target operation
46   * </ul>
47   *
48   * <h5 class='section'>Example:</h5>
49   * <p class='bjava'>
50   * 	<jc>// Create a link to another operation</jc>
51   * 	Link <jv>link</jv> = <jk>new</jk> Link()
52   * 		.setOperationId(<js>"getUserById"</js>)
53   * 		.setParameters(
54   * 			JsonMap.<jsm>of</jsm>(<js>"userId"</js>, <js>"$response.body#/id"</js>)
55   * 		)
56   * 		.setDescription(<js>"The id value returned in the response can be used as userId parameter in GET /users/{userId}"</js>);
57   * </p>
58   *
59   * <h5 class='section'>See Also:</h5><ul>
60   * 	<li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#link-object">OpenAPI Specification &gt; Link Object</a>
61   * 	<li class='link'><a class="doclink" href="https://swagger.io/docs/specification/links/">OpenAPI Links</a>
62   * 	<li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
63   * </ul>
64   */
65  public class Link extends OpenApiElement {
66  
67  	private String operationRef;
68  	private String operationId;
69  	private String description;
70  	private Object requestBody;
71  	private Server server;
72  	private Map<String,Object> parameters = map();
73  
74  	/**
75  	 * Default constructor.
76  	 */
77  	public Link() {}
78  
79  	/**
80  	 * Copy constructor.
81  	 *
82  	 * @param copyFrom The object to copy.
83  	 */
84  	public Link(Link copyFrom) {
85  		super(copyFrom);
86  
87  		this.operationRef = copyFrom.operationRef;
88  		this.description = copyFrom.description;
89  		this.operationId = copyFrom.operationId;
90  		this.requestBody = copyFrom.requestBody;
91  		this.server = copyFrom.server == null ? null : copyFrom.server.copy();
92  		if (nn(copyFrom.parameters))
93  			parameters.putAll(copyFrom.parameters);
94  	}
95  
96  	/**
97  	 * Adds a single value to the <property>examples</property> property.
98  	 *
99  	 * @param mimeType The mime-type string.  Must not be <jk>null</jk>.
100 	 * @param parameter The example.  Must not be <jk>null</jk>.
101 	 * @return This object
102 	 */
103 	public Link addParameter(String mimeType, Object parameter) {
104 		assertArgNotNull("mimeType", mimeType);
105 		assertArgNotNull("parameter", parameter);
106 		parameters.put(mimeType, parameter);
107 		return this;
108 	}
109 
110 	/**
111 	 * Make a deep copy of this object.
112 	 *
113 	 * @return A deep copy of this object.
114 	 */
115 	public Link copy() {
116 		return new Link(this);
117 	}
118 
119 	@Override /* Overridden from OpenApiElement */
120 	public <T> T get(String property, Class<T> type) {
121 		assertArgNotNull("property", property);
122 		return switch (property) {
123 			case "description" -> toType(getDescription(), type);
124 			case "operationRef" -> toType(getOperationRef(), type);
125 			case "operationId" -> toType(getOperationId(), type);
126 			case "requestBody" -> toType(getRequestBody(), type);
127 			case "parameters" -> toType(getParameters(), type);
128 			case "server" -> toType(getServer(), type);
129 			default -> super.get(property, type);
130 		};
131 	}
132 
133 	/**
134 	 * Bean property getter:  <property>description</property>.
135 	 *
136 	 * <p>
137 	 * The URL pointing to the contact information.
138 	 *
139 	 * @return The property value, or <jk>null</jk> if it is not set.
140 	 */
141 	public String getDescription() { return description; }
142 
143 	/**
144 	 * Bean property getter:  <property>externalValue</property>.
145 	 *
146 	 * <p>
147 	 * The email address of the contact person/organization.
148 	 *
149 	 * @return The property value, or <jk>null</jk> if it is not set.
150 	 */
151 	public String getOperationId() { return operationId; }
152 
153 	/**
154 	 * Bean property getter:  <property>operationRef</property>.
155 	 *
156 	 * <p>
157 	 * The identifying name of the contact person/organization.
158 	 *
159 	 * @return The property value, or <jk>null</jk> if it is not set.
160 	 */
161 	public String getOperationRef() { return operationRef; }
162 
163 	/**
164 	 * Bean property getter:  <property>examples</property>.
165 	 *
166 	 * <p>
167 	 * An example of the response message.
168 	 *
169 	 * @return The property value, or <jk>null</jk> if it is not set.
170 	 */
171 	public Map<String,Object> getParameters() { return nullIfEmpty(parameters); }
172 
173 	/**
174 	 * Bean property getter:  <property>default</property>.
175 	 *
176 	 * <p>
177 	 * Declares the value of the parameter that the server will use if none is provided, for example a <js>"count"</js>
178 	 * to control the number of results per page might default to 100 if not supplied by the client in the request.
179 	 *
180 	 * (Note: <js>"value"</js> has no meaning for required parameters.)
181 	 * Unlike JSON Schema this value MUST conform to the defined <code>type</code> for this parameter.
182 	 *
183 	 * @return The property value, or <jk>null</jk> if it is not set.
184 	 */
185 	public Object getRequestBody() { return requestBody; }
186 
187 	/**
188 	 * Bean property getter:  <property>additionalProperties</property>.
189 	 *
190 	 * @return The property value, or <jk>null</jk> if it is not set.
191 	 */
192 	public Server getServer() { return server; }
193 
194 	@Override /* Overridden from OpenApiElement */
195 	public Set<String> keySet() {
196 		// @formatter:off
197 		var s = setb(String.class)
198 			.addIf(nn(description), "description")
199 			.addIf(nn(operationId), "operationId")
200 			.addIf(nn(operationRef), "operationRef")
201 			.addIf(ne(parameters), "parameters")
202 			.addIf(nn(requestBody), "requestBody")
203 			.addIf(nn(server), "server")
204 			.build();
205 		// @formatter:on
206 		return new MultiSet<>(s, super.keySet());
207 	}
208 
209 	@Override /* Overridden from OpenApiElement */
210 	public Link set(String property, Object value) {
211 		assertArgNotNull("property", property);
212 		return switch (property) {
213 			case "description" -> setDescription(s(value));
214 			case "operationId" -> setOperationId(s(value));
215 			case "operationRef" -> setOperationRef(s(value));
216 			case "parameters" -> setParameters(toMapBuilder(value, String.class, Object.class).sparse().build());
217 			case "requestBody" -> setRequestBody(value);
218 			case "server" -> setServer(toType(value, Server.class));
219 			default -> {
220 				super.set(property, value);
221 				yield this;
222 			}
223 		};
224 	}
225 
226 	/**
227 	 * Bean property setter:  <property>description</property>.
228 	 * @param value
229 	 * 	The new value for this property.
230 	 * 	<br>Can be <jk>null</jk> to unset the property.
231 	 * @return This object
232 	 */
233 	public Link setDescription(String value) {
234 		description = value;
235 		return this;
236 	}
237 
238 	/**
239 	 * Bean property setter:  <property>externalValue</property>.
240 	 *
241 	 * <p>
242 	 * The email address of the contact person/organization.
243 	 *
244 	 * @param value
245 	 * 	The new value for this property.
246 	 * 	<br>MUST be in the format of an email address.
247 	 * 	<br>Can be <jk>null</jk> to unset the property.
248 	 * @return This object
249 	 */
250 	public Link setOperationId(String value) {
251 		operationId = value;
252 		return this;
253 	}
254 
255 	/**
256 	 * Bean property setter:  <property>operationRef</property>.
257 	 *
258 	 * <p>
259 	 * The identifying name of the contact person/organization.
260 	 *
261 	 * @param value
262 	 * 	The new value for this property.
263 	 * 	<br>Can be <jk>null</jk> to unset the property.
264 	 * @return This object
265 	 */
266 	public Link setOperationRef(String value) {
267 		operationRef = value;
268 		return this;
269 	}
270 
271 	/**
272 	 * Bean property setter:  <property>examples</property>.
273 	 *
274 	 * <p>
275 	 * An example of the response message.
276 	 *
277 	 * @param value
278 	 * 	The new value for this property.
279 	 * 	<br>Keys must be MIME-type strings.
280 	 * 	<br>Can be <jk>null</jk> to unset the property.
281 	 * @return This object
282 	 */
283 	public Link setParameters(Map<String,Object> value) {
284 		parameters.clear();
285 		if (nn(value))
286 			parameters.putAll(value);
287 		return this;
288 	}
289 
290 	/**
291 	 * Bean property setter:  <property>value</property>.
292 	 *
293 	 * <p>
294 	 * Declares the value of the parameter that the server will use if none is provided, for example a <js>"count"</js>
295 	 * to control the number of results per page might default to 100 if not supplied by the client in the request.
296 	 * (Note: <js>"default"</js> has no meaning for required parameters.)
297 	 * Unlike JSON Schema this value MUST conform to the defined <code>type</code> for this parameter.
298 	 *
299 	 * @param val The new value for this property.
300 	 * 	<br>Can be <jk>null</jk> to unset the property.
301 	 * @return This object
302 	 */
303 	public Link setRequestBody(Object val) {
304 		requestBody = val;
305 		return this;
306 	}
307 
308 	/**
309 	 * Bean property setter:  <property>additionalProperties</property>.
310 	 *
311 	 * @param value
312 	 * 	The new value for this property.
313 	 * 	<br>Can be <jk>null</jk> to unset the property.
314 	 * @return This object
315 	 */
316 	public Link setServer(Server value) {
317 		server = value;
318 		return this;
319 	}
320 
321 	@Override /* Overridden from OpenApiElement */
322 	public Link strict() {
323 		super.strict();
324 		return this;
325 	}
326 
327 	@Override /* Overridden from OpenApiElement */
328 	public Link strict(Object value) {
329 		super.strict(value);
330 		return this;
331 	}
332 }