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}