You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2022/08/18 12:20:54 UTC

[cxf] 01/04: CXF-8750: only add trailing slash if necessary when locating webjars … (#982)

This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 728ccbf3489ef9d5015e6eb3ad269e35d7df8c9a
Author: Aleksy Wróblewski <34...@users.noreply.github.com>
AuthorDate: Sun Aug 14 19:13:14 2022 +0200

    CXF-8750: only add trailing slash if necessary when locating webjars … (#982)
    
    * CXF-8750: only add trailing slash if necessary when locating webjars resources for Swagger UI in OSGi environment
    
    * CXF-8750: read response body directly via Response.getEntity
    
    Co-authored-by: Aleksy Wróblewski <al...@bbbit.io>
---
 osgi/itests/pom.xml                                |  9 ++++
 .../apache/cxf/osgi/itests/jaxrs/BookStore.java    | 48 ++++++++++++++++++++++
 .../cxf/osgi/itests/jaxrs/JaxRsServiceTest.java    | 46 +++++++++++++++++++--
 .../cxf/osgi/itests/jaxrs/JaxRsTestActivator.java  | 11 ++++-
 .../jaxrs/swagger/ui/OsgiSwaggerUiResolver.java    |  4 +-
 5 files changed, 113 insertions(+), 5 deletions(-)

diff --git a/osgi/itests/pom.xml b/osgi/itests/pom.xml
index 77d6809744..6b0e982dac 100644
--- a/osgi/itests/pom.xml
+++ b/osgi/itests/pom.xml
@@ -56,10 +56,19 @@
             <groupId>org.apache.cxf</groupId>
             <artifactId>cxf-rt-transports-jms</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-rs-service-description-openapi-v3</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.activemq</groupId>
             <artifactId>activemq-client</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.webjars</groupId>
+            <artifactId>swagger-ui</artifactId>
+            <version>${cxf.swagger.ui.version}</version>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.karaf</groupId>
diff --git a/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/BookStore.java b/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/BookStore.java
index b7ace0bc49..6b15968659 100644
--- a/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/BookStore.java
+++ b/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/BookStore.java
@@ -50,7 +50,14 @@ import org.apache.cxf.validation.BeanValidationProvider;
 import org.hibernate.validator.HibernateValidator;
 import org.hibernate.validator.HibernateValidatorConfiguration;
 
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
 @Path("/bookstore")
+@Tag(name = "BookStore")
 @Produces("application/xml")
 public class BookStore {
     private Map<Long, Book> books = new HashMap<>();
@@ -73,6 +80,15 @@ public class BookStore {
 
     @GET
     @Path("/books/{id}")
+    @Operation(
+            summary = "Get book by ID",
+            description = "Get operation with path parameter",
+            responses = {
+                @ApiResponse(content = @Content(schema = @Schema(implementation = Book.class)),
+                    description = "Book found", responseCode = "200"),
+                @ApiResponse(description = "Book not found", responseCode = "404")
+            }
+    )
     public Response getBookRoot(@PathParam("id") Long id) {
         assertInjections();
         Book b = books.get(id);
@@ -82,6 +98,14 @@ public class BookStore {
         return Response.ok(b).build();
     }
 
+    @Operation(
+            summary = "Update book by ID",
+            description = "Put operation with path parameter",
+            responses = {
+                @ApiResponse(description = "Book found and updated", responseCode = "200"),
+                @ApiResponse(description = "Book not found", responseCode = "404")
+            }
+    )
     @PUT
     @Path("/books/{id}")
     public Response updateBook(@PathParam("id") Long id, Book book) {
@@ -94,6 +118,14 @@ public class BookStore {
         return Response.ok().build();
     }
 
+    @Operation(
+            summary = "Create a book with validation",
+            description = "Post operation with entity in body and validation",
+            responses = {
+                @ApiResponse(description = "Book created", responseCode = "201"),
+                @ApiResponse(description = "Validation failed", responseCode = "400")
+            }
+    )
     @POST
     @Path("/books-validate")
     public Response createBookValidate(Book book) {
@@ -124,6 +156,14 @@ public class BookStore {
     }
 
 
+    @Operation(
+            summary = "Create new book",
+            description = "Post operation with entity in body",
+            responses = {
+                @ApiResponse(description = "Book created", responseCode = "201"),
+                @ApiResponse(description = "Book with given ID already exists", responseCode = "409")
+            }
+    )
     @POST
     @Path("/books")
     public Response createBook(Book book) {
@@ -138,6 +178,14 @@ public class BookStore {
         return Response.created(createdURI).build();
     }
 
+    @Operation(
+            summary = "Delete a book",
+            description = "Delete operation with path param",
+            responses = {
+                @ApiResponse(description = "Book deleted", responseCode = "200"),
+                @ApiResponse(description = "Book not found", responseCode = "404")
+            }
+    )
     @DELETE
     @Path("/books/{id}")
     public Response removeBook(@PathParam("id") Long id) {
diff --git a/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/JaxRsServiceTest.java b/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/JaxRsServiceTest.java
index 0b749c77dd..b2d3de36ea 100644
--- a/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/JaxRsServiceTest.java
+++ b/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/JaxRsServiceTest.java
@@ -26,6 +26,9 @@ import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 import org.apache.cxf.helpers.JavaUtils;
 import org.apache.cxf.osgi.itests.AbstractServerActivator;
 import org.apache.cxf.osgi.itests.CXFOSGiTestSupport;
@@ -44,6 +47,9 @@ import org.ops4j.pax.tinybundles.core.TinyBundles;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
 import static org.ops4j.pax.exam.CoreOptions.provision;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.features;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
@@ -53,9 +59,12 @@ import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
 @ExamReactorStrategy(PerClass.class)
 public class JaxRsServiceTest extends CXFOSGiTestSupport {
 
-    private static final String BASE_URL = "http://localhost:" + PORT + "/cxf/jaxrs/bookstore";
+    private static final String BASE_URL = "http://localhost:" + PORT + "/cxf/jaxrs/";
+    private static final String BOOKSTORE_URL = BASE_URL + "bookstore";
+    private static final String SWAGGER_URL = BASE_URL + "api-docs";
+    private static final String OPEN_API_FILE_URL = BASE_URL + "openapi.json";
 
-    private final WebTarget wt = ClientBuilder.newClient().target(BASE_URL);
+    private final WebTarget wt = ClientBuilder.newClient().target(BOOKSTORE_URL);
 
     @Test
     public void testJaxRsGet() throws Exception {
@@ -99,6 +108,35 @@ public class JaxRsServiceTest extends CXFOSGiTestSupport {
         assertStatus(Status.OK, response);
     }
 
+    @Test
+    public void testGetSwaggerUi() {
+        WebTarget swaggerWt = ClientBuilder.newClient().target(SWAGGER_URL)
+                .queryParam("url", "/cxf/jaxrs/openapi.json");
+        Response response = swaggerWt.request().get();
+        String swaggerFileHtml = response.readEntity(String.class);
+
+        assertStatus(Status.OK, response);
+        assertTrue(swaggerFileHtml.contains("<html"));
+        assertTrue(swaggerFileHtml.contains("<head>"));
+        assertTrue(swaggerFileHtml.contains("<title>Swagger UI</title>"));
+        assertTrue(swaggerFileHtml.contains("</html>"));
+    }
+
+    @Test
+    public void testGetOpenApiJsonFile() {
+        WebTarget openApiWt = ClientBuilder.newClient().target(OPEN_API_FILE_URL);
+        Response response = openApiWt.request().get();
+        String openApiJson = response.readEntity(String.class);
+
+        assertStatus(Status.OK, response);
+        try {
+            new ObjectMapper().readValue(openApiJson, Object.class);
+            assertTrue(openApiJson.contains("/bookstore/"));
+        } catch (JsonProcessingException e) {
+            fail();
+        }
+    }
+
     private static void assertStatus(Status expectedStatus, Response response) {
         assertEquals(expectedStatus.getStatusCode(), response.getStatus());
     }
@@ -107,7 +145,9 @@ public class JaxRsServiceTest extends CXFOSGiTestSupport {
     public Option[] config() {
         return OptionUtils.combine(
             cxfBaseConfig(),
-            features(cxfUrl, "cxf-core", "cxf-wsdl", "cxf-jaxrs", "cxf-bean-validation-core", "cxf-bean-validation"),
+            features(cxfUrl, "cxf-core", "cxf-wsdl", "cxf-jaxrs", "cxf-bean-validation-core", "cxf-bean-validation",
+                    "cxf-rs-description-openapi-v3"),
+            mavenBundle("org.webjars", "swagger-ui").versionAsInProject(),
             logLevel(LogLevel.INFO),
             testUtils(),
             provision(serviceBundle())
diff --git a/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/JaxRsTestActivator.java b/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/JaxRsTestActivator.java
index 4a28390f21..5e9238c09f 100644
--- a/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/JaxRsTestActivator.java
+++ b/osgi/itests/src/test/java/org/apache/cxf/osgi/itests/jaxrs/JaxRsTestActivator.java
@@ -22,6 +22,8 @@ import org.apache.cxf.Bus;
 import org.apache.cxf.BusFactory;
 import org.apache.cxf.endpoint.Server;
 import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.openapi.OpenApiFeature;
+import org.apache.cxf.jaxrs.swagger.ui.SwaggerUiConfig;
 import org.apache.cxf.osgi.itests.AbstractServerActivator;
 
 public class JaxRsTestActivator extends AbstractServerActivator {
@@ -33,8 +35,15 @@ public class JaxRsTestActivator extends AbstractServerActivator {
         JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
         sf.setBus(bus);
         sf.setResourceClasses(BookStore.class);
+        OpenApiFeature openApiFeature = new OpenApiFeature();
+        openApiFeature.setScan(false);
+        openApiFeature.setUseContextBasedConfig(true);
+        SwaggerUiConfig swaggerUiConfig = new SwaggerUiConfig();
+        swaggerUiConfig.setUrl("/cxf/jaxrs/openapi.json");
+        openApiFeature.setSwaggerUiConfig(swaggerUiConfig);
+
+        sf.getFeatures().add(openApiFeature);
         sf.setAddress("/jaxrs");
         return sf.create();
     }
-
 }
diff --git a/rt/rs/description-swagger-ui/src/main/java/org/apache/cxf/jaxrs/swagger/ui/OsgiSwaggerUiResolver.java b/rt/rs/description-swagger-ui/src/main/java/org/apache/cxf/jaxrs/swagger/ui/OsgiSwaggerUiResolver.java
index efb0456559..c494beea4b 100644
--- a/rt/rs/description-swagger-ui/src/main/java/org/apache/cxf/jaxrs/swagger/ui/OsgiSwaggerUiResolver.java
+++ b/rt/rs/description-swagger-ui/src/main/java/org/apache/cxf/jaxrs/swagger/ui/OsgiSwaggerUiResolver.java
@@ -88,7 +88,9 @@ public class OsgiSwaggerUiResolver extends SwaggerUiResolver {
         }
         URL entry = b.getEntry(SwaggerUiResolver.UI_RESOURCES_ROOT_START + swaggerUiVersion);
         if (entry != null) {
-            return entry.toString() + "/";
+            String entryAsString = entry.toString();
+            // add the trailing slash if it is missing, it depends on OSGi version/implementation
+            return entryAsString.endsWith("/") ? entryAsString : entryAsString + "/";
         }
         return null;
     }