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.Utils.*;
020import static org.apache.juneau.internal.CollectionUtils.*;
021import static org.apache.juneau.internal.ConverterUtils.*;
022
023import java.util.*;
024
025import org.apache.juneau.internal.*;
026
027/**
028 * Holds a set of reusable objects for different aspects of the OpenAPI Specification.
029 *
030 * <p>
031 * The Components Object holds a set of reusable objects that can be referenced from other parts of the API specification.
032 * This promotes reusability and reduces duplication by allowing common schemas, responses, parameters, and other objects
033 * to be defined once and referenced multiple times using the <c>$ref</c> syntax.
034 *
035 * <h5 class='section'>OpenAPI Specification:</h5>
036 * <p>
037 * The Components Object is composed of the following fields:
038 * <ul class='spaced-list'>
039 *    <li><c>schemas</c> (map of {@link SchemaInfo}) - Reusable schema definitions
040 *    <li><c>responses</c> (map of {@link Response}) - Reusable response definitions
041 *    <li><c>parameters</c> (map of {@link Parameter}) - Reusable parameter definitions
042 *    <li><c>examples</c> (map of {@link Example}) - Reusable example definitions
043 *    <li><c>requestBodies</c> (map of {@link RequestBodyInfo}) - Reusable request body definitions
044 *    <li><c>headers</c> (map of {@link HeaderInfo}) - Reusable header definitions
045 *    <li><c>securitySchemes</c> (map of {@link SecuritySchemeInfo}) - Reusable security scheme definitions
046 *    <li><c>links</c> (map of {@link Link}) - Reusable link definitions
047 *    <li><c>callbacks</c> (map of {@link Callback}) - Reusable callback definitions
048 * </ul>
049 *
050 * <h5 class='section'>Example:</h5>
051 * <p class='bjava'>
052 *    <jc>// Create a Components object with reusable schemas</jc>
053 *    Components <jv>components</jv> = <jk>new</jk> Components()
054 *       .setSchemas(
055 *          JsonMap.<jsm>of</jsm>(
056 *             <js>"Pet"</js>, <jk>new</jk> SchemaInfo()
057 *                .setType(<js>"object"</js>)
058 *                .setRequired(<js>"id"</js>, <js>"name"</js>)
059 *                .setProperties(
060 *                   JsonMap.<jsm>of</jsm>(
061 *                      <js>"id"</js>, <jk>new</jk> SchemaInfo().setType(<js>"integer"</js>),
062 *                      <js>"name"</js>, <jk>new</jk> SchemaInfo().setType(<js>"string"</js>)
063 *                   )
064 *                ),
065 *             <js>"Error"</js>, <jk>new</jk> SchemaInfo()
066 *                .setType(<js>"object"</js>)
067 *                .setProperties(
068 *                   JsonMap.<jsm>of</jsm>(
069 *                      <js>"code"</js>, <jk>new</jk> SchemaInfo().setType(<js>"integer"</js>),
070 *                      <js>"message"</js>, <jk>new</jk> SchemaInfo().setType(<js>"string"</js>)
071 *                   )
072 *                )
073 *          )
074 *       );
075 *    <jc>// These schemas can then be referenced: "#/components/schemas/Pet"</jc>
076 * </p>
077 *
078 * <h5 class='section'>See Also:</h5><ul>
079 *    <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#components-object">OpenAPI Specification &gt; Components Object</a>
080 *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/components/">OpenAPI Components</a>
081 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
082 * </ul>
083 */
084public class Components extends OpenApiElement {
085
086   private Map<String,SchemaInfo> schemas;
087   private Map<String,Response> responses;
088   private Map<String,Parameter> parameters;
089   private Map<String,Example> examples;
090   private Map<String,RequestBodyInfo> requestBodies;
091   private Map<String,HeaderInfo> headers;
092   private Map<String,SecuritySchemeInfo> securitySchemes;
093   private Map<String,Link> links;
094   private Map<String,Callback> callbacks;
095
096   /**
097    * Default constructor.
098    */
099   public Components() {}
100
101   /**
102    * Copy constructor.
103    *
104    * @param copyFrom The object to copy.
105    */
106   public Components(Components copyFrom) {
107      super(copyFrom);
108      this.schemas = copyOf(copyFrom.schemas);
109      this.responses = copyOf(copyFrom.responses);
110      this.parameters = copyOf(copyFrom.parameters);
111      this.examples = copyOf(copyFrom.examples);
112      this.requestBodies = copyOf(copyFrom.requestBodies);
113      this.headers = copyOf(copyFrom.headers);
114      this.securitySchemes = copyOf(copyFrom.securitySchemes);
115      this.links = copyOf(copyFrom.links);
116      this.callbacks = copyOf(copyFrom.callbacks);
117   }
118
119   /**
120    * Returns the schemas map.
121    *
122    * @return The schemas map.
123    */
124   public Map<String,SchemaInfo> getSchemas() {
125      return schemas;
126   }
127
128   /**
129    * Sets the schemas map.
130    *
131    * @param value The new value for this property.
132    * @return This object.
133    */
134   public Components setSchemas(Map<String,SchemaInfo> value) {
135      this.schemas = value;
136      return this;
137   }
138
139   /**
140    * Returns the responses map.
141    *
142    * @return The responses map.
143    */
144   public Map<String,Response> getResponses() {
145      return responses;
146   }
147
148   /**
149    * Sets the responses map.
150    *
151    * @param value The new value for this property.
152    * @return This object.
153    */
154   public Components setResponses(Map<String,Response> value) {
155      this.responses = value;
156      return this;
157   }
158
159   /**
160    * Returns the parameters map.
161    *
162    * @return The parameters map.
163    */
164   public Map<String,Parameter> getParameters() {
165      return parameters;
166   }
167
168   /**
169    * Sets the parameters map.
170    *
171    * @param value The new value for this property.
172    * @return This object.
173    */
174   public Components setParameters(Map<String,Parameter> value) {
175      this.parameters = value;
176      return this;
177   }
178
179   /**
180    * Returns the examples map.
181    *
182    * @return The examples map.
183    */
184   public Map<String,Example> getExamples() {
185      return examples;
186   }
187
188   /**
189    * Sets the examples map.
190    *
191    * @param value The new value for this property.
192    * @return This object.
193    */
194   public Components setExamples(Map<String,Example> value) {
195      this.examples = value;
196      return this;
197   }
198
199   /**
200    * Returns the request bodies map.
201    *
202    * @return The request bodies map.
203    */
204   public Map<String,RequestBodyInfo> getRequestBodies() {
205      return requestBodies;
206   }
207
208   /**
209    * Sets the request bodies map.
210    *
211    * @param value The new value for this property.
212    * @return This object.
213    */
214   public Components setRequestBodies(Map<String,RequestBodyInfo> value) {
215      this.requestBodies = value;
216      return this;
217   }
218
219   /**
220    * Returns the headers map.
221    *
222    * @return The headers map.
223    */
224   public Map<String,HeaderInfo> getHeaders() {
225      return headers;
226   }
227
228   /**
229    * Sets the headers map.
230    *
231    * @param value The new value for this property.
232    * @return This object.
233    */
234   public Components setHeaders(Map<String,HeaderInfo> value) {
235      this.headers = value;
236      return this;
237   }
238
239   /**
240    * Returns the security schemes map.
241    *
242    * @return The security schemes map.
243    */
244   public Map<String,SecuritySchemeInfo> getSecuritySchemes() {
245      return securitySchemes;
246   }
247
248   /**
249    * Sets the security schemes map.
250    *
251    * @param value The new value for this property.
252    * @return This object.
253    */
254   public Components setSecuritySchemes(Map<String,SecuritySchemeInfo> value) {
255      this.securitySchemes = value;
256      return this;
257   }
258
259   /**
260    * Returns the links map.
261    *
262    * @return The links map.
263    */
264   public Map<String,Link> getLinks() {
265      return links;
266   }
267
268   /**
269    * Sets the links map.
270    *
271    * @param value The new value for this property.
272    * @return This object.
273    */
274   public Components setLinks(Map<String,Link> value) {
275      this.links = value;
276      return this;
277   }
278
279   /**
280    * Returns the callbacks map.
281    *
282    * @return The callbacks map.
283    */
284   public Map<String,Callback> getCallbacks() {
285      return callbacks;
286   }
287
288   /**
289    * Sets the callbacks map.
290    *
291    * @param value The new value for this property.
292    * @return This object.
293    */
294   public Components setCallbacks(Map<String,Callback> value) {
295      this.callbacks = value;
296      return this;
297   }
298
299   /**
300    * Creates a copy of this object.
301    *
302    * @return A copy of this object.
303    */
304   public Components copy() {
305      return new Components(this);
306   }
307
308   @Override /* Overridden from OpenApiElement */
309   public <T> T get(String property, Class<T> type) {
310      assertArgNotNull("property", property);
311      return switch (property) {
312         case "schemas" -> toType(getSchemas(), type);
313         case "responses" -> toType(getResponses(), type);
314         case "parameters" -> toType(getParameters(), type);
315         case "examples" -> toType(getExamples(), type);
316         case "requestBodies" -> toType(getRequestBodies(), type);
317         case "headers" -> toType(getHeaders(), type);
318         case "securitySchemes" -> toType(getSecuritySchemes(), type);
319         case "links" -> toType(getLinks(), type);
320         case "callbacks" -> toType(getCallbacks(), type);
321         default -> super.get(property, type);
322      };
323   }
324
325   @Override /* Overridden from OpenApiElement */
326   public Components set(String property, Object value) {
327      assertArgNotNull("property", property);
328      return switch (property) {
329         case "callbacks" -> setCallbacks(mapBuilder(String.class, Callback.class).sparse().addAny(value).build());
330         case "examples" -> setExamples(mapBuilder(String.class, Example.class).sparse().addAny(value).build());
331         case "headers" -> setHeaders(mapBuilder(String.class, HeaderInfo.class).sparse().addAny(value).build());
332         case "links" -> setLinks(mapBuilder(String.class, Link.class).sparse().addAny(value).build());
333         case "parameters" -> setParameters(mapBuilder(String.class, Parameter.class).sparse().addAny(value).build());
334         case "requestBodies" -> setRequestBodies(mapBuilder(String.class, RequestBodyInfo.class).sparse().addAny(value).build());
335         case "responses" -> setResponses(mapBuilder(String.class, Response.class).sparse().addAny(value).build());
336         case "schemas" -> setSchemas(mapBuilder(String.class, SchemaInfo.class).sparse().addAny(value).build());
337         case "securitySchemes" -> setSecuritySchemes(mapBuilder(String.class, SecuritySchemeInfo.class).sparse().addAny(value).build());
338         default -> {
339            super.set(property, value);
340            yield this;
341         }
342      };
343   }
344
345   @Override /* Overridden from OpenApiElement */
346   public Set<String> keySet() {
347      var s = setBuilder(String.class)
348         .addIf(callbacks != null, "callbacks")
349         .addIf(examples != null, "examples")
350         .addIf(headers != null, "headers")
351         .addIf(links != null, "links")
352         .addIf(parameters != null, "parameters")
353         .addIf(requestBodies != null, "requestBodies")
354         .addIf(responses != null, "responses")
355         .addIf(schemas != null, "schemas")
356         .addIf(securitySchemes != null, "securitySchemes")
357         .build();
358      return new MultiSet<>(s, super.keySet());
359   }
360
361   @Override /* Overridden from OpenApiElement */
362   public Components strict() {
363      super.strict();
364      return this;
365   }
366
367   @Override /* Overridden from OpenApiElement */
368   public Components strict(Object value) {
369      super.strict(value);
370      return this;
371   }
372}