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.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.Utils.*;
022import static org.apache.juneau.internal.ConverterUtils.*;
023
024import java.util.*;
025
026import org.apache.juneau.commons.collections.*;
027
028/**
029 * Holds a set of reusable objects for different aspects of the OpenAPI Specification.
030 *
031 * <p>
032 * The Components Object holds a set of reusable objects that can be referenced from other parts of the API specification.
033 * This promotes reusability and reduces duplication by allowing common schemas, responses, parameters, and other objects
034 * to be defined once and referenced multiple times using the <c>$ref</c> syntax.
035 *
036 * <h5 class='section'>OpenAPI Specification:</h5>
037 * <p>
038 * The Components Object is composed of the following fields:
039 * <ul class='spaced-list'>
040 *    <li><c>schemas</c> (map of {@link SchemaInfo}) - Reusable schema definitions
041 *    <li><c>responses</c> (map of {@link Response}) - Reusable response definitions
042 *    <li><c>parameters</c> (map of {@link Parameter}) - Reusable parameter definitions
043 *    <li><c>examples</c> (map of {@link Example}) - Reusable example definitions
044 *    <li><c>requestBodies</c> (map of {@link RequestBodyInfo}) - Reusable request body definitions
045 *    <li><c>headers</c> (map of {@link HeaderInfo}) - Reusable header definitions
046 *    <li><c>securitySchemes</c> (map of {@link SecuritySchemeInfo}) - Reusable security scheme definitions
047 *    <li><c>links</c> (map of {@link Link}) - Reusable link definitions
048 *    <li><c>callbacks</c> (map of {@link Callback}) - Reusable callback definitions
049 * </ul>
050 *
051 * <h5 class='section'>Example:</h5>
052 * <p class='bjava'>
053 *    <jc>// Create a Components object with reusable schemas</jc>
054 *    Components <jv>components</jv> = <jk>new</jk> Components()
055 *       .setSchemas(
056 *          JsonMap.<jsm>of</jsm>(
057 *             <js>"Pet"</js>, <jk>new</jk> SchemaInfo()
058 *                .setType(<js>"object"</js>)
059 *                .setRequired(<js>"id"</js>, <js>"name"</js>)
060 *                .setProperties(
061 *                   JsonMap.<jsm>of</jsm>(
062 *                      <js>"id"</js>, <jk>new</jk> SchemaInfo().setType(<js>"integer"</js>),
063 *                      <js>"name"</js>, <jk>new</jk> SchemaInfo().setType(<js>"string"</js>)
064 *                   )
065 *                ),
066 *             <js>"Error"</js>, <jk>new</jk> SchemaInfo()
067 *                .setType(<js>"object"</js>)
068 *                .setProperties(
069 *                   JsonMap.<jsm>of</jsm>(
070 *                      <js>"code"</js>, <jk>new</jk> SchemaInfo().setType(<js>"integer"</js>),
071 *                      <js>"message"</js>, <jk>new</jk> SchemaInfo().setType(<js>"string"</js>)
072 *                   )
073 *                )
074 *          )
075 *       );
076 *    <jc>// These schemas can then be referenced: "#/components/schemas/Pet"</jc>
077 * </p>
078 *
079 * <h5 class='section'>See Also:</h5><ul>
080 *    <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#components-object">OpenAPI Specification &gt; Components Object</a>
081 *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/components/">OpenAPI Components</a>
082 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
083 * </ul>
084 */
085public class Components extends OpenApiElement {
086
087   private Map<String,SchemaInfo> schemas;
088   private Map<String,Response> responses;
089   private Map<String,Parameter> parameters;
090   private Map<String,Example> examples;
091   private Map<String,RequestBodyInfo> requestBodies;
092   private Map<String,HeaderInfo> headers;
093   private Map<String,SecuritySchemeInfo> securitySchemes;
094   private Map<String,Link> links;
095   private Map<String,Callback> callbacks;
096
097   /**
098    * Default constructor.
099    */
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}