This is an automated email from the ASF dual-hosted git repository. reta pushed a commit to branch CXF-7601_microProfileOpenApi in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 7b333d06910b3d4a84dd77a3c76b48d1b44525b3 Author: Dennis Kieselhorst <[email protected]> AuthorDate: Wed Jan 23 14:41:54 2019 +0100 [CXF-7601] Add support for Microprofile OpenAPI implementation (as an alternative to Swagger Core 2.0) --- rt/rs/description-microprofile-openapi/pom.xml | 99 +++++ .../cxf/jaxrs/mpopenapi/OpenApiEndpoint.java | 43 ++ .../apache/cxf/jaxrs/mpopenapi/OpenApiFeature.java | 474 +++++++++++++++++++++ .../cxf/jaxrs/mpopenapi/SwaggerProperties.java | 69 +++ .../org/apache/cxf/jaxrs/mpopenapi/SwaggerUi.java | 47 ++ rt/rs/pom.xml | 1 + 6 files changed, 733 insertions(+) diff --git a/rt/rs/description-microprofile-openapi/pom.xml b/rt/rs/description-microprofile-openapi/pom.xml new file mode 100644 index 0000000..e505aad --- /dev/null +++ b/rt/rs/description-microprofile-openapi/pom.xml @@ -0,0 +1,99 @@ +<?xml version="1.0"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <artifactId>cxf-rt-rs-service-description-microprofile-openapi</artifactId> + <packaging>jar</packaging> + <name>Apache CXF JAX-RS Service Description Microprofile OpenAPI</name> + <description>Apache CXF JAX-RS Service Description Microprofile OpenAPI</description> + <url>http://cxf.apache.org</url> + <parent> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-parent</artifactId> + <version>3.3.0-SNAPSHOT</version> + <relativePath>../../../parent/pom.xml</relativePath> + </parent> + <properties> + <cxf.module.name>org.apache.cxf.rs.openapi.microprofile</cxf.module.name> + </properties> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${cxf.servlet-api.group}</groupId> + <artifactId>${cxf.servlet-api.artifact}</artifactId> + <scope>provided</scope> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-frontend-jaxrs</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-rs-service-description-swagger-ui</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-rs-json-basic</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.eclipse.microprofile.openapi</groupId> + <artifactId>microprofile-openapi-api</artifactId> + <version>1.0.1</version> + </dependency> + <dependency> + <groupId>org.apache.geronimo</groupId> + <artifactId>geronimo-openapi-impl</artifactId> + <version>1.0.5-SNAPSHOT</version> + </dependency> + <!--<dependency>--> + <!--<groupId>org.apache.geronimo.specs</groupId>--> + <!--<artifactId>geronimo-jsonb_1.0_spec</artifactId>--> + <!--<version>1.0</version>--> + <!--<scope>compile</scope>--> + <!--</dependency>--> + <!--<dependency>--> + <!--<groupId>org.apache.geronimo.specs</groupId>--> + <!--<artifactId>geronimo-json_1.1_spec</artifactId>--> + <!--<version>1.0</version>--> + <!--<scope>compile</scope>--> + <!--</dependency>--> + <!--<dependency>--> + <!--<groupId>org.apache.johnzon</groupId>--> + <!--<artifactId>johnzon-jsonb</artifactId>--> + <!--<version>${cxf.johnzon.version}</version>--> + <!--</dependency>--> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + <optional>true</optional> + </dependency> + </dependencies> +</project> diff --git a/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiEndpoint.java b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiEndpoint.java new file mode 100644 index 0000000..6b82611 --- /dev/null +++ b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiEndpoint.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.jaxrs.mpopenapi; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.apache.geronimo.microprofile.openapi.jaxrs.OpenAPIEndpoint; +import org.eclipse.microprofile.openapi.models.OpenAPI; + +@Path("/openapi.{type:json|yaml}") +public class OpenApiEndpoint extends OpenAPIEndpoint { + private OpenAPI openApi; + + public OpenApiEndpoint(OpenAPI openApi) { + this.openApi = openApi; + } + + @Override + @GET + @Produces({MediaType.APPLICATION_JSON, "application/yaml"}) + public OpenAPI get() { + return openApi; + } +} diff --git a/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiFeature.java b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiFeature.java new file mode 100644 index 0000000..c65fd9b --- /dev/null +++ b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiFeature.java @@ -0,0 +1,474 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.jaxrs.mpopenapi; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.ws.rs.core.Application; + +import org.apache.cxf.Bus; +import org.apache.cxf.annotations.Provider; +import org.apache.cxf.annotations.Provider.Scope; +import org.apache.cxf.annotations.Provider.Type; +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.endpoint.Server; +import org.apache.cxf.feature.AbstractFeature; +import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean; +import org.apache.cxf.jaxrs.model.AbstractResourceInfo; +import org.apache.cxf.jaxrs.model.ApplicationInfo; +import org.apache.cxf.jaxrs.model.ClassResourceInfo; +import org.apache.cxf.jaxrs.provider.ServerProviderFactory; +import org.apache.cxf.jaxrs.swagger.ui.SwaggerUiConfig; +import org.apache.cxf.jaxrs.swagger.ui.SwaggerUiSupport; +import org.apache.geronimo.microprofile.openapi.config.GeronimoOpenAPIConfig; +import org.apache.geronimo.microprofile.openapi.impl.model.ContactImpl; +import org.apache.geronimo.microprofile.openapi.impl.model.InfoImpl; +import org.apache.geronimo.microprofile.openapi.impl.model.LicenseImpl; +import org.apache.geronimo.microprofile.openapi.impl.model.OpenAPIImpl; +import org.apache.geronimo.microprofile.openapi.impl.processor.AnnotationProcessor; +import org.apache.geronimo.microprofile.openapi.impl.processor.reflect.ClassElement; +import org.apache.geronimo.microprofile.openapi.impl.processor.reflect.MethodElement; +import org.apache.geronimo.microprofile.openapi.impl.processor.spi.NamingStrategy; +import org.eclipse.microprofile.openapi.models.OpenAPI; + + +@Provider(value = Type.Feature, scope = Scope.Server) +public class OpenApiFeature extends AbstractFeature implements SwaggerUiSupport, SwaggerProperties { + private static final Logger LOG = LogUtils.getL7dLogger(OpenApiFeature.class); + + private static final String DEFAULT_PROPS_LOCATION = "/swagger.properties"; + + private String version; + private String title; + private String description; + private String contactName; + private String contactEmail; + private String contactUrl; + private String license; + private String licenseUrl; + private String termsOfServiceUrl; + // Read all operations also with no @Operation + private boolean readAllResources = true; + // Scan all JAX-RS resources automatically + private boolean scan = true; + private boolean prettyPrint = true; + private boolean runAsFilter; + private Collection<String> ignoredRoutes; + private Set<String> resourcePackages; + private Set<String> resourceClasses; + private String filterClass; + + private Boolean supportSwaggerUi; + private String swaggerUiVersion; + private String swaggerUiMavenGroupAndArtifact; + private Map<String, String> swaggerUiMediaTypes; + + // Allows to pass the configuration location, usually openapi-configuration.json + // or openapi-configuration.yml file. + private String configLocation; + // Allows to pass the properties location, by default swagger.properties + private String propertiesLocation = DEFAULT_PROPS_LOCATION; + // Allows to disable automatic scan of known configuration locations (enabled by default) + private boolean scanKnownConfigLocations = true; + // Swagger UI configuration parameters (to be passed as query string). + private SwaggerUiConfig swaggerUiConfig; + + protected static class DefaultApplication extends Application { + + private final Set<Class<?>> serviceClasses; + + DefaultApplication(final List<ClassResourceInfo> cris, final Set<String> resourcePackages) { + this.serviceClasses = cris.stream().map(ClassResourceInfo::getServiceClass). + filter(cls -> (resourcePackages == null || resourcePackages.isEmpty()) || resourcePackages.stream(). + anyMatch(pkg -> cls.getPackage().getName().startsWith(pkg))).collect(Collectors.toSet()); + } + + @Override + public Set<Class<?>> getClasses() { + return serviceClasses; + } + } + + @Override + public void initialize(Server server, Bus bus) { + final JAXRSServiceFactoryBean sfb = (JAXRSServiceFactoryBean)server + .getEndpoint() + .get(JAXRSServiceFactoryBean.class.getName()); + + final ServerProviderFactory factory = (ServerProviderFactory)server + .getEndpoint() + .get(ServerProviderFactory.class.getName()); + + final Set<String> packages = new HashSet<>(); + if (resourcePackages != null) { + packages.addAll(resourcePackages); + } + + final Application application = getApplicationOrDefault(server, factory, sfb, bus); + + final AnnotationProcessor processor = new AnnotationProcessor(GeronimoOpenAPIConfig.create(), + new NamingStrategy.Http()); + + final OpenAPIImpl api = new OpenAPIImpl(); + + if (isScan()) { + packages.addAll(scanResourcePackages(sfb)); + } + if (application != null) { + processor.processApplication(api, new ClassElement(application.getClass())); + LOG.fine("Processed application " + application); + } + Set<Class<?>> endpointClasses = sfb + .getClassResourceInfo() + .stream() + .map(AbstractResourceInfo::getServiceClass) + .collect(Collectors.toSet()); + if (!endpointClasses.isEmpty()) { + final String binding = application == null ? "" : processor.getApplicationBinding(application.getClass()); + endpointClasses.stream() + .peek(c -> LOG.info("Processing class " + c.getName())) + .forEach(c -> processor.processClass( + binding, api, new ClassElement(c), + Stream.of(c.getMethods()).map(MethodElement::new))); + } else { + LOG.warning("No <endpointClasses> registered, your OpenAPI will be empty."); + } + Properties swaggerProps = getSwaggerProperties(propertiesLocation, bus); + if (api.getInfo() == null) { + api.setInfo(getInfo(swaggerProps)); + } + + registerOpenApiResources(sfb, api); + registerSwaggerUiResources(sfb, swaggerProps, factory, bus); + } + + public boolean isScan() { + return scan; + } + + public void setScan(boolean scan) { + this.scan = scan; + } + + public String getFilterClass() { + return filterClass; + } + + public void setFilterClass(String filterClass) { + this.filterClass = filterClass; + } + + public Set<String> getResourcePackages() { + return resourcePackages; + } + + public void setResourcePackages(Set<String> resourcePackages) { + this.resourcePackages = (resourcePackages == null) ? null : new HashSet<>(resourcePackages); + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getContactName() { + return contactName; + } + + public void setContactName(String contactName) { + this.contactName = contactName; + } + + public String getContactEmail() { + return contactEmail; + } + + public void setContactEmail(String contactEmail) { + this.contactEmail = contactEmail; + } + + public String getContactUrl() { + return contactUrl; + } + + public void setContactUrl(String contactUrl) { + this.contactUrl = contactUrl; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getLicenseUrl() { + return licenseUrl; + } + + public void setLicenseUrl(String licenseUrl) { + this.licenseUrl = licenseUrl; + } + + public String getTermsOfServiceUrl() { + return termsOfServiceUrl; + } + + public void setTermsOfServiceUrl(String termsOfServiceUrl) { + this.termsOfServiceUrl = termsOfServiceUrl; + } + + public boolean isReadAllResources() { + return readAllResources; + } + + public void setReadAllResources(boolean readAllResources) { + this.readAllResources = readAllResources; + } + + public Set<String> getResourceClasses() { + return resourceClasses; + } + + public void setResourceClasses(Set<String> resourceClasses) { + this.resourceClasses = (resourceClasses == null) ? null : new HashSet<>(resourceClasses); + } + + public Collection<String> getIgnoredRoutes() { + return ignoredRoutes; + } + + public void setIgnoredRoutes(Collection<String> ignoredRoutes) { + this.ignoredRoutes = (ignoredRoutes == null) ? null : new HashSet<>(ignoredRoutes); + } + + public boolean isPrettyPrint() { + return prettyPrint; + } + + public void setPrettyPrint(boolean prettyPrint) { + this.prettyPrint = prettyPrint; + } + + public boolean isRunAsFilter() { + return runAsFilter; + } + + @Override + public Boolean isSupportSwaggerUi() { + return supportSwaggerUi; + } + + public void setSupportSwaggerUi(Boolean supportSwaggerUi) { + this.supportSwaggerUi = supportSwaggerUi; + } + + public String getSwaggerUiVersion() { + return swaggerUiVersion; + } + + public void setSwaggerUiVersion(String swaggerUiVersion) { + this.swaggerUiVersion = swaggerUiVersion; + } + + public String getSwaggerUiMavenGroupAndArtifact() { + return swaggerUiMavenGroupAndArtifact; + } + + public void setSwaggerUiMavenGroupAndArtifact( + String swaggerUiMavenGroupAndArtifact) { + this.swaggerUiMavenGroupAndArtifact = swaggerUiMavenGroupAndArtifact; + } + + @Override + public Map<String, String> getSwaggerUiMediaTypes() { + return swaggerUiMediaTypes; + } + + public void setSwaggerUiMediaTypes(Map<String, String> swaggerUiMediaTypes) { + this.swaggerUiMediaTypes = swaggerUiMediaTypes; + } + + public String getConfigLocation() { + return configLocation; + } + + public void setConfigLocation(String configLocation) { + this.configLocation = configLocation; + } + + public String getPropertiesLocation() { + return propertiesLocation; + } + + public void setPropertiesLocation(String propertiesLocation) { + this.propertiesLocation = propertiesLocation; + } + + public void setRunAsFilter(boolean runAsFilter) { + this.runAsFilter = runAsFilter; + } + + public void setScanKnownConfigLocations(boolean scanKnownConfigLocations) { + this.scanKnownConfigLocations = scanKnownConfigLocations; + } + + public boolean isScanKnownConfigLocations() { + return scanKnownConfigLocations; + } + + public void setSwaggerUiConfig(final SwaggerUiConfig swaggerUiConfig) { + this.swaggerUiConfig = swaggerUiConfig; + } + + @Override + public SwaggerUiConfig getSwaggerUiConfig() { + return swaggerUiConfig; + } + + @Override + public String findSwaggerUiRoot() { + return SwaggerUi.findSwaggerUiRoot(swaggerUiMavenGroupAndArtifact, swaggerUiVersion); + } + + protected Properties getUserProperties(final Map<String, Object> userDefinedOptions) { + final Properties properties = new Properties(); + + if (userDefinedOptions != null) { + userDefinedOptions + .entrySet() + .stream() + .filter(entry -> entry.getValue() != null) + .forEach(entry -> properties.setProperty(entry.getKey(), entry.getValue().toString())); + } + + return properties; + } + + protected void registerOpenApiResources( + final JAXRSServiceFactoryBean sfb, + final OpenAPI openApiDefinition) { + + sfb.setResourceClassesFromBeans(Collections.singletonList(new OpenApiEndpoint(openApiDefinition))); + } + + protected void registerSwaggerUiResources(JAXRSServiceFactoryBean sfb, Properties properties, + ServerProviderFactory factory, Bus bus) { + + final Registration swaggerUiRegistration = getSwaggerUi(bus, properties, isRunAsFilter()); + + if (!isRunAsFilter()) { + sfb.setResourceClassesFromBeans(swaggerUiRegistration.getResources()); + } + + factory.setUserProviders(swaggerUiRegistration.getProviders()); + } + + /** + * Detects the application (if present) or creates the default application (in case the scan is disabled). + */ + protected Application getApplicationOrDefault( + final Server server, + final ServerProviderFactory factory, + final JAXRSServiceFactoryBean sfb, + final Bus bus) { + + ApplicationInfo appInfo = null; + if (!isScan()) { + appInfo = factory.getApplicationProvider(); + + if (appInfo == null) { + appInfo = new ApplicationInfo( + new DefaultApplication(sfb.getClassResourceInfo(), resourcePackages), bus); + server.getEndpoint().put(Application.class.getName(), appInfo); + } + } + + return (appInfo == null) ? null : appInfo.getProvider(); + } + + /** + * The info will be used only if there is no @OpenAPIDefinition annotation is present. + */ + private org.eclipse.microprofile.openapi.models.info.Info getInfo(final Properties properties) { + org.eclipse.microprofile.openapi.models.info.Info info = new InfoImpl() + .title(getOrFallback(getTitle(), properties, TITLE_PROPERTY)) + .version(getOrFallback(getVersion(), properties, VERSION_PROPERTY)) + .description(getOrFallback(getDescription(), properties, DESCRIPTION_PROPERTY)) + .termsOfService(getOrFallback(getTermsOfServiceUrl(), properties, TERMS_URL_PROPERTY)) + .contact(new ContactImpl() + .name(getOrFallback(getContactName(), properties, CONTACT_PROPERTY)) + .email(getContactEmail()) + .url(getContactUrl())); + + String licenseName = getOrFallback(getLicense(), properties, LICENSE_PROPERTY); + if (licenseName != null) { + info = info.license(new LicenseImpl() + .name(getOrFallback(getLicense(), properties, LICENSE_PROPERTY)) + .url(getOrFallback(getLicenseUrl(), properties, LICENSE_URL_PROPERTY))); + } + return info; + } + + private String getOrFallback(String value, Properties properties, String property) { + if (value == null && properties != null) { + return properties.getProperty(property); + } else { + return value; + } + } + + private Collection<String> scanResourcePackages(JAXRSServiceFactoryBean sfb) { + return sfb + .getClassResourceInfo() + .stream() + .map(cri -> cri.getServiceClass().getPackage().getName()) + .collect(Collectors.toSet()); + } + +} diff --git a/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerProperties.java b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerProperties.java new file mode 100644 index 0000000..c4b4c2a --- /dev/null +++ b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerProperties.java @@ -0,0 +1,69 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cxf.jaxrs.mpopenapi; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.apache.cxf.Bus; +import org.apache.cxf.jaxrs.utils.ResourceUtils; + +interface SwaggerProperties { + String RESOURCE_PACKAGE_PROPERTY = "resource.package"; + String TITLE_PROPERTY = "title"; + String VERSION_PROPERTY = "version"; + String DESCRIPTION_PROPERTY = "description"; + String CONTACT_PROPERTY = "contact"; + String LICENSE_PROPERTY = "license"; + String LICENSE_URL_PROPERTY = "license.url"; + String TERMS_URL_PROPERTY = "terms.url"; + String PRETTY_PRINT_PROPERTY = "pretty.print"; + String FILTER_CLASS_PROPERTY = "filter.class"; + + /** + * Read the Swagger-specific properties from the property file (to seamlessly + * support the migration from older Swagger features). + * @param location property file location + * @param bus bus instance + * @return the properties if available + */ + default Properties getSwaggerProperties(String location, Bus bus) { + InputStream is = ResourceUtils.getClasspathResourceStream(location, SwaggerProperties.class, bus); + Properties props = null; + + if (is != null) { + props = new Properties(); + try { + props.load(is); + } catch (IOException ex) { + props = null; + } finally { + try { + is.close(); + } catch (IOException ignore) { + // ignore + } + } + } + + return props; + } +} diff --git a/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerUi.java b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerUi.java new file mode 100644 index 0000000..f796dfb --- /dev/null +++ b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerUi.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cxf.jaxrs.mpopenapi; + +import org.apache.cxf.jaxrs.swagger.ui.SwaggerUiResolver; + +/** + * SwaggerUI resolvers implementation for OpenAPI + */ +public final class SwaggerUi { + private static final SwaggerUiResolver HELPER; + + static { + HELPER = new SwaggerUiResolver(OpenApiFeature.class.getClassLoader()); + } + + private SwaggerUi() { + } + + public static String findSwaggerUiRoot(String swaggerUiMavenGroupAndArtifact, + String swaggerUiVersion) { + String root = HELPER.findSwaggerUiRootInternal(swaggerUiMavenGroupAndArtifact, + swaggerUiVersion); + if (root == null && HELPER.getClass() != SwaggerUiResolver.class) { + root = new SwaggerUiResolver(OpenApiFeature.class.getClassLoader()) + .findSwaggerUiRootInternal(swaggerUiMavenGroupAndArtifact, swaggerUiVersion); + } + return root; + } +} diff --git a/rt/rs/pom.xml b/rt/rs/pom.xml index 7dfbf5b..9dd53ba 100644 --- a/rt/rs/pom.xml +++ b/rt/rs/pom.xml @@ -44,6 +44,7 @@ <module>security</module> <module>sse</module> <module>description-openapi-v3</module> + <module>description-microprofile-openapi</module> <module>description-swagger-ui</module> <module>microprofile-client</module> <module>description-common-openapi</module>
