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.rest.server.openapi;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.*;
022import java.util.function.*;
023
024import org.apache.juneau.bean.openapi3.*;
025import org.apache.juneau.commons.inject.*;
026import org.apache.juneau.commons.svl.*;
027import org.apache.juneau.http.response.*;
028import org.apache.juneau.marshall.cp.*;
029import org.apache.juneau.marshall.jsonschema.*;
030import org.apache.juneau.rest.server.*;
031
032/**
033 * Interface for retrieving an {@link OpenApi} 3.1 document from a REST resource.
034 *
035 * <p>
036 * Sibling of {@link org.apache.juneau.rest.server.swagger.SwaggerProvider} for OpenAPI 3.1 emission. Both
037 * providers coexist; the {@code @Rest(openApiProvider=...)} attribute selects the implementation.
038 *
039 * <h5 class='section'>See Also:</h5><ul>
040 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/ApiDocsMixins">API-Docs Mixin Pack</a>
041 * </ul>
042 */
043@SuppressWarnings({
044   "java:S9398" // Nested types are public API; moving them would break callers.
045})
046public interface OpenApiProvider {
047
048   /**
049    * Builder class for {@link OpenApiProvider} instances.
050    */
051   public class Builder {
052
053      final BeanStore beanStore;
054      Class<?> resourceClass;
055      Supplier<VarResolver> varResolver;
056      Supplier<JsonSchemaGenerator> jsonSchemaGenerator;
057      Supplier<Messages> messages;
058      Supplier<FileFinder> fileFinder;
059      private OpenApiProvider impl;
060      private Class<? extends OpenApiProvider> implType;
061
062      /**
063       * Constructor.
064       *
065       * @param beanStore The bean store to use for creating beans.
066       */
067      protected Builder(BeanStore beanStore) {
068         this.beanStore = beanStore;
069      }
070
071      /**
072       * Creates a new {@link OpenApiProvider} object from this builder.
073       *
074       * <p>
075       * Instantiates an instance of the {@link #type(Class) implementation class} or
076       * else {@link BasicOpenApiProvider} if implementation class was not specified.
077       *
078       * @return A new {@link OpenApiProvider} object.
079       */
080      public OpenApiProvider build() {
081         try {
082            if (impl != null)
083               return impl;
084            var t = or(implType, BasicOpenApiProvider.class);
085            return BeanInstantiator.of(OpenApiProvider.class, beanStore)
086               .type(t)
087               .noBuilder()
088               .addBean(Builder.class, this)
089               .run();
090         } catch (Exception e) {
091            throw new InternalServerError(e);
092         }
093      }
094
095      /**
096       * Returns the file finder in this builder if it's been specified.
097       *
098       * @return The file finder.
099       */
100      public Optional<FileFinder> fileFinder() {
101         return o(fileFinder).map(Supplier::get);
102      }
103
104      /**
105       * Specifies the file-finder to use for the {@link OpenApiProvider} object.
106       *
107       * @param value The new value for this setting.
108       * @return  This object.
109       */
110      public Builder fileFinder(Supplier<FileFinder> value) {
111         fileFinder = value;
112         return this;
113      }
114
115      /**
116       * Specifies an already-instantiated bean for the {@link #build()} method to return.
117       *
118       * @param value The new value for this setting.
119       *    <br>Can be <jk>null</jk> (the {@link #build()} method instantiates the {@link #type(Class) type} instead).
120       * @return  This object.
121       */
122      public Builder impl(OpenApiProvider value) {
123         this.impl = value;
124         return this;
125      }
126
127      /**
128       * Returns the JSON schema generator in this builder if it's been specified.
129       *
130       * @return The JSON schema generator.
131       */
132      public Optional<JsonSchemaGenerator> jsonSchemaGenerator() {
133         return o(jsonSchemaGenerator).map(Supplier::get);
134      }
135
136      /**
137       * Specifies the JSON-schema generator to use for the {@link OpenApiProvider} object.
138       *
139       * @param value The new value for this setting.
140       * @return  This object.
141       */
142      public Builder jsonSchemaGenerator(Supplier<JsonSchemaGenerator> value) {
143         jsonSchemaGenerator = value;
144         return this;
145      }
146
147      /**
148       * Returns the messages in this builder if it's been specified.
149       *
150       * @return The messages.
151       */
152      public Optional<Messages> messages() {
153         return o(messages).map(Supplier::get);
154      }
155
156      /**
157       * Specifies the messages to use for the {@link OpenApiProvider} object.
158       *
159       * @param value The new value for this setting.
160       * @return  This object.
161       */
162      public Builder messages(Supplier<Messages> value) {
163         messages = value;
164         return this;
165      }
166
167      /**
168       * Specifies a subclass of {@link OpenApiProvider} to create when the {@link #build()} method is called.
169       *
170       * @param value The new value for this setting.
171       *    <br>Can be <jk>null</jk> (defaults to {@link BasicOpenApiProvider}).
172       * @return  This object.
173       */
174      public Builder type(Class<? extends OpenApiProvider> value) {
175         implType = o(value).isPresent() ? value : BasicOpenApiProvider.class;
176         return this;
177      }
178
179      /**
180       * Returns the var resolver in this builder if it's been specified.
181       *
182       * @return The var resolver.
183       */
184      public Optional<VarResolver> varResolver() {
185         return o(varResolver).map(Supplier::get);
186      }
187
188      /**
189       * Specifies the variable resolver to use for the {@link OpenApiProvider} object.
190       *
191       * @param value The new value for this setting.
192       * @return  This object.
193       */
194      public Builder varResolver(Supplier<VarResolver> value) {
195         varResolver = value;
196         return this;
197      }
198
199      /**
200       * Specifies the default implementation class if not specified via {@link #type(Class)}.
201       *
202       * @return The default implementation class if not specified via {@link #type(Class)}.
203       */
204      protected Class<? extends OpenApiProvider> getDefaultType() { return BasicOpenApiProvider.class; }
205   }
206
207   /**
208    * Represents no OpenApiProvider.
209    *
210    * <p>
211    * Used on annotation to indicate that the value should be inherited from the parent class, and
212    * ultimately {@link BasicOpenApiProvider} if not specified at any level.
213    */
214   @SuppressWarnings({
215      "java:S9398" // Public annotation-default marker; moving breaks API.
216   })
217   public abstract class Void implements OpenApiProvider {}
218
219   /**
220    * Static creator.
221    *
222    * @param beanStore The bean store to use for creating beans.
223    * @return A new builder for this object.
224    */
225   static Builder create(BeanStore beanStore) {
226      return new Builder(beanStore);
227   }
228
229   /**
230    * Returns the OpenAPI 3.1 document associated with the specified {@link Rest}-annotated class.
231    *
232    * @param context The context of the {@link Rest}-annotated class.
233    * @param locale The request locale.
234    * @return A new {@link OpenApi} DTO object.
235    * @throws Exception If an error occurred producing the document.
236    */
237   @SuppressWarnings({
238      "java:S112" // throws Exception intentional - callback/lifecycle method
239   })
240   OpenApi getOpenApi(RestContext context, Locale locale) throws Exception;
241}