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   * Holds a set of reusable objects for different aspects of the OpenAPI Specification.
30   *
31   * <p>
32   * The Components Object holds a set of reusable objects that can be referenced from other parts of the API specification.
33   * This promotes reusability and reduces duplication by allowing common schemas, responses, parameters, and other objects
34   * to be defined once and referenced multiple times using the <c>$ref</c> syntax.
35   *
36   * <h5 class='section'>OpenAPI Specification:</h5>
37   * <p>
38   * The Components Object is composed of the following fields:
39   * <ul class='spaced-list'>
40   * 	<li><c>schemas</c> (map of {@link SchemaInfo}) - Reusable schema definitions
41   * 	<li><c>responses</c> (map of {@link Response}) - Reusable response definitions
42   * 	<li><c>parameters</c> (map of {@link Parameter}) - Reusable parameter definitions
43   * 	<li><c>examples</c> (map of {@link Example}) - Reusable example definitions
44   * 	<li><c>requestBodies</c> (map of {@link RequestBodyInfo}) - Reusable request body definitions
45   * 	<li><c>headers</c> (map of {@link HeaderInfo}) - Reusable header definitions
46   * 	<li><c>securitySchemes</c> (map of {@link SecuritySchemeInfo}) - Reusable security scheme definitions
47   * 	<li><c>links</c> (map of {@link Link}) - Reusable link definitions
48   * 	<li><c>callbacks</c> (map of {@link Callback}) - Reusable callback definitions
49   * </ul>
50   *
51   * <h5 class='section'>Example:</h5>
52   * <p class='bjava'>
53   * 	<jc>// Create a Components object with reusable schemas</jc>
54   * 	Components <jv>components</jv> = <jk>new</jk> Components()
55   * 		.setSchemas(
56   * 			JsonMap.<jsm>of</jsm>(
57   * 				<js>"Pet"</js>, <jk>new</jk> SchemaInfo()
58   * 					.setType(<js>"object"</js>)
59   * 					.setRequired(<js>"id"</js>, <js>"name"</js>)
60   * 					.setProperties(
61   * 						JsonMap.<jsm>of</jsm>(
62   * 							<js>"id"</js>, <jk>new</jk> SchemaInfo().setType(<js>"integer"</js>),
63   * 							<js>"name"</js>, <jk>new</jk> SchemaInfo().setType(<js>"string"</js>)
64   * 						)
65   * 					),
66   * 				<js>"Error"</js>, <jk>new</jk> SchemaInfo()
67   * 					.setType(<js>"object"</js>)
68   * 					.setProperties(
69   * 						JsonMap.<jsm>of</jsm>(
70   * 							<js>"code"</js>, <jk>new</jk> SchemaInfo().setType(<js>"integer"</js>),
71   * 							<js>"message"</js>, <jk>new</jk> SchemaInfo().setType(<js>"string"</js>)
72   * 						)
73   * 					)
74   * 			)
75   * 		);
76   * 	<jc>// These schemas can then be referenced: "#/components/schemas/Pet"</jc>
77   * </p>
78   *
79   * <h5 class='section'>See Also:</h5><ul>
80   * 	<li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#components-object">OpenAPI Specification &gt; Components Object</a>
81   * 	<li class='link'><a class="doclink" href="https://swagger.io/docs/specification/components/">OpenAPI Components</a>
82   * 	<li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
83   * </ul>
84   */
85  public class Components extends OpenApiElement {
86  
87  	private Map<String,SchemaInfo> schemas;
88  	private Map<String,Response> responses;
89  	private Map<String,Parameter> parameters;
90  	private Map<String,Example> examples;
91  	private Map<String,RequestBodyInfo> requestBodies;
92  	private Map<String,HeaderInfo> headers;
93  	private Map<String,SecuritySchemeInfo> securitySchemes;
94  	private Map<String,Link> links;
95  	private Map<String,Callback> callbacks;
96  
97  	/**
98  	 * Default constructor.
99  	 */
100 	public Components() {}
101 
102 	/**
103 	 * Copy constructor.
104 	 *
105 	 * @param copyFrom The object to copy.
106 	 */
107 	public Components(Components copyFrom) {
108 		super(copyFrom);
109 		this.schemas = copyOf(copyFrom.schemas);
110 		this.responses = copyOf(copyFrom.responses);
111 		this.parameters = copyOf(copyFrom.parameters);
112 		this.examples = copyOf(copyFrom.examples);
113 		this.requestBodies = copyOf(copyFrom.requestBodies);
114 		this.headers = copyOf(copyFrom.headers);
115 		this.securitySchemes = copyOf(copyFrom.securitySchemes);
116 		this.links = copyOf(copyFrom.links);
117 		this.callbacks = copyOf(copyFrom.callbacks);
118 	}
119 
120 	/**
121 	 * Creates a copy of this object.
122 	 *
123 	 * @return A copy of this object.
124 	 */
125 	public Components copy() {
126 		return new Components(this);
127 	}
128 
129 	@Override /* Overridden from OpenApiElement */
130 	public <T> T get(String property, Class<T> type) {
131 		assertArgNotNull("property", property);
132 		return switch (property) {
133 			case "schemas" -> toType(getSchemas(), type);
134 			case "responses" -> toType(getResponses(), type);
135 			case "parameters" -> toType(getParameters(), type);
136 			case "examples" -> toType(getExamples(), type);
137 			case "requestBodies" -> toType(getRequestBodies(), type);
138 			case "headers" -> toType(getHeaders(), type);
139 			case "securitySchemes" -> toType(getSecuritySchemes(), type);
140 			case "links" -> toType(getLinks(), type);
141 			case "callbacks" -> toType(getCallbacks(), type);
142 			default -> super.get(property, type);
143 		};
144 	}
145 
146 	/**
147 	 * Returns the callbacks map.
148 	 *
149 	 * @return The callbacks map.
150 	 */
151 	public Map<String,Callback> getCallbacks() { return callbacks; }
152 
153 	/**
154 	 * Returns the examples map.
155 	 *
156 	 * @return The examples map.
157 	 */
158 	public Map<String,Example> getExamples() { return examples; }
159 
160 	/**
161 	 * Returns the headers map.
162 	 *
163 	 * @return The headers map.
164 	 */
165 	public Map<String,HeaderInfo> getHeaders() { return headers; }
166 
167 	/**
168 	 * Returns the links map.
169 	 *
170 	 * @return The links map.
171 	 */
172 	public Map<String,Link> getLinks() { return links; }
173 
174 	/**
175 	 * Returns the parameters map.
176 	 *
177 	 * @return The parameters map.
178 	 */
179 	public Map<String,Parameter> getParameters() { return parameters; }
180 
181 	/**
182 	 * Returns the request bodies map.
183 	 *
184 	 * @return The request bodies map.
185 	 */
186 	public Map<String,RequestBodyInfo> getRequestBodies() { return requestBodies; }
187 
188 	/**
189 	 * Returns the responses map.
190 	 *
191 	 * @return The responses map.
192 	 */
193 	public Map<String,Response> getResponses() { return responses; }
194 
195 	/**
196 	 * Returns the schemas map.
197 	 *
198 	 * @return The schemas map.
199 	 */
200 	public Map<String,SchemaInfo> getSchemas() { return schemas; }
201 
202 	/**
203 	 * Returns the security schemes map.
204 	 *
205 	 * @return The security schemes map.
206 	 */
207 	public Map<String,SecuritySchemeInfo> getSecuritySchemes() { return securitySchemes; }
208 
209 	@Override /* Overridden from OpenApiElement */
210 	public Set<String> keySet() {
211 		// @formatter:off
212 		var s = setb(String.class)
213 			.addIf(nn(callbacks), "callbacks")
214 			.addIf(nn(examples), "examples")
215 			.addIf(nn(headers), "headers")
216 			.addIf(nn(links), "links")
217 			.addIf(nn(parameters), "parameters")
218 			.addIf(nn(requestBodies), "requestBodies")
219 			.addIf(nn(responses), "responses")
220 			.addIf(nn(schemas), "schemas")
221 			.addIf(nn(securitySchemes), "securitySchemes")
222 			.build();
223 		// @formatter:on
224 		return new MultiSet<>(s, super.keySet());
225 	}
226 
227 	@Override /* Overridden from OpenApiElement */
228 	public Components set(String property, Object value) {
229 		assertArgNotNull("property", property);
230 		return switch (property) {
231 			case "callbacks" -> setCallbacks(toMapBuilder(value, String.class, Callback.class).sparse().build());
232 			case "examples" -> setExamples(toMapBuilder(value, String.class, Example.class).sparse().build());
233 			case "headers" -> setHeaders(toMapBuilder(value, String.class, HeaderInfo.class).sparse().build());
234 			case "links" -> setLinks(toMapBuilder(value, String.class, Link.class).sparse().build());
235 			case "parameters" -> setParameters(toMapBuilder(value, String.class, Parameter.class).sparse().build());
236 			case "requestBodies" -> setRequestBodies(toMapBuilder(value, String.class, RequestBodyInfo.class).sparse().build());
237 			case "responses" -> setResponses(toMapBuilder(value, String.class, Response.class).sparse().build());
238 			case "schemas" -> setSchemas(toMapBuilder(value, String.class, SchemaInfo.class).sparse().build());
239 			case "securitySchemes" -> setSecuritySchemes(toMapBuilder(value, String.class, SecuritySchemeInfo.class).sparse().build());
240 			default -> {
241 				super.set(property, value);
242 				yield this;
243 			}
244 		};
245 	}
246 
247 	/**
248 	 * Sets the callbacks map.
249 	 *
250 	 * @param value The new value for this property.
251 	 * @return This object.
252 	 */
253 	public Components setCallbacks(Map<String,Callback> value) {
254 		callbacks = value;
255 		return this;
256 	}
257 
258 	/**
259 	 * Sets the examples map.
260 	 *
261 	 * @param value The new value for this property.
262 	 * @return This object.
263 	 */
264 	public Components setExamples(Map<String,Example> value) {
265 		examples = value;
266 		return this;
267 	}
268 
269 	/**
270 	 * Sets the headers map.
271 	 *
272 	 * @param value The new value for this property.
273 	 * @return This object.
274 	 */
275 	public Components setHeaders(Map<String,HeaderInfo> value) {
276 		headers = value;
277 		return this;
278 	}
279 
280 	/**
281 	 * Sets the links map.
282 	 *
283 	 * @param value The new value for this property.
284 	 * @return This object.
285 	 */
286 	public Components setLinks(Map<String,Link> value) {
287 		links = value;
288 		return this;
289 	}
290 
291 	/**
292 	 * Sets the parameters map.
293 	 *
294 	 * @param value The new value for this property.
295 	 * @return This object.
296 	 */
297 	public Components setParameters(Map<String,Parameter> value) {
298 		parameters = value;
299 		return this;
300 	}
301 
302 	/**
303 	 * Sets the request bodies map.
304 	 *
305 	 * @param value The new value for this property.
306 	 * @return This object.
307 	 */
308 	public Components setRequestBodies(Map<String,RequestBodyInfo> value) {
309 		requestBodies = value;
310 		return this;
311 	}
312 
313 	/**
314 	 * Sets the responses map.
315 	 *
316 	 * @param value The new value for this property.
317 	 * @return This object.
318 	 */
319 	public Components setResponses(Map<String,Response> value) {
320 		responses = value;
321 		return this;
322 	}
323 
324 	/**
325 	 * Sets the schemas map.
326 	 *
327 	 * @param value The new value for this property.
328 	 * @return This object.
329 	 */
330 	public Components setSchemas(Map<String,SchemaInfo> value) {
331 		schemas = value;
332 		return this;
333 	}
334 
335 	/**
336 	 * Sets the security schemes map.
337 	 *
338 	 * @param value The new value for this property.
339 	 * @return This object.
340 	 */
341 	public Components setSecuritySchemes(Map<String,SecuritySchemeInfo> value) {
342 		securitySchemes = value;
343 		return this;
344 	}
345 
346 	@Override /* Overridden from OpenApiElement */
347 	public Components strict() {
348 		super.strict();
349 		return this;
350 	}
351 
352 	@Override /* Overridden from OpenApiElement */
353 	public Components strict(Object value) {
354 		super.strict(value);
355 		return this;
356 	}
357 }