CXF-6740: Collision by Swagger2Feature in two OSGI bundles
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/3e30d889 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/3e30d889 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/3e30d889 Branch: refs/heads/master-jaxrs-2.1 Commit: 3e30d8892a723adcf04268efd7d407e164607065 Parents: 7283581 Author: reta <[email protected]> Authored: Wed Mar 9 16:46:15 2016 -0500 Committer: reta <[email protected]> Committed: Sun Aug 21 20:15:00 2016 -0400 ---------------------------------------------------------------------- .../jax_rs/description_swagger2_osgi/README.txt | 11 +- .../jax_rs/description_swagger2_osgi/pom.xml | 4 + .../resources/OSGI-INF/blueprint/context.xml | 1 + .../README.txt | 47 ++++++ .../pom.xml | 151 +++++++++++++++++++ .../jaxrs/swagger/server/ApiOriginFilter.java | 45 ++++++ .../java/demo/jaxrs/swagger/server/Item.java | 49 ++++++ .../java/demo/jaxrs/swagger/server/Server.java | 93 ++++++++++++ .../main/java/demo/jaxrs/swagger/v1/Sample.java | 141 +++++++++++++++++ .../main/java/demo/jaxrs/swagger/v2/Sample.java | 140 +++++++++++++++++ .../META-INF/cxf/org.apache.cxf.Logger | 1 + .../src/main/resources/logback.xml | 16 ++ distribution/src/main/release/samples/pom.xml | 1 + parent/pom.xml | 2 +- .../cxf/jaxrs/swagger/Swagger2Feature.java | 72 ++++++++- 15 files changed, 765 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/README.txt ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/README.txt b/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/README.txt index a0cc407..85f5e73 100644 --- a/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/README.txt +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/README.txt @@ -47,9 +47,18 @@ for this demo bundle. feature:install cxf-rs-description-swagger2 Install this demo bundle (using the appropriate bundle version number) - + install -s mvn:org.apache.cxf.samples/jax_rs_description_swagger2_osgi/3.n.m +Optionally, installed the following bundles if they are missed: + + install -s mvn:com.fasterxml.jackson.core/jackson-core/2.4.6 + install -s mvn:com.fasterxml.jackson.core/jackson-annotations/2.4.6 + install -s mvn:com.fasterxml.jackson.core/jackson-databind/2.4.6 + install -s mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/2.4.6 + install -s mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/2.4.6 + install -s mvn:javax.annotation/javax.annotation-api/1.2 + You can verify if the CXF JAX-RS Swagger2 Blueprint Demo is installed and started. karaf@root()> list http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/pom.xml ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/pom.xml b/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/pom.xml index 575e675..8820ea4 100644 --- a/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/pom.xml +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/pom.xml @@ -46,6 +46,7 @@ under the License. <Import-Package> javax.ws.rs, javax.ws.rs.core, + javax.ws.rs.container, org.apache.cxf.jaxrs.provider, org.apache.cxf.jaxrs.swagger, org.osgi.service.blueprint, @@ -53,6 +54,9 @@ under the License. io.swagger.models, io.swagger.jaxrs.config, io.swagger.jaxrs.listing, + com.fasterxml.jackson.jaxrs.base, + com.fasterxml.jackson.jaxrs.json, + javax.annotation;version="[1.2,2)", * </Import-Package> <Export-Package> http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/src/main/resources/OSGI-INF/blueprint/context.xml ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/src/main/resources/OSGI-INF/blueprint/context.xml b/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/src/main/resources/OSGI-INF/blueprint/context.xml index d60db84..b3f0245 100644 --- a/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/src/main/resources/OSGI-INF/blueprint/context.xml +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_osgi/src/main/resources/OSGI-INF/blueprint/context.xml @@ -40,6 +40,7 @@ <!-- CXF Swagger2Feature --> <bean id="swagger2Feature" class="org.apache.cxf.jaxrs.swagger.Swagger2Feature"> <property name="basePath" value="/cxf/swaggerSample"/> + <property name="usePathBasedConfig" value="true" /> </bean> <cxf:bus> http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/README.txt ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/README.txt b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/README.txt new file mode 100644 index 0000000..89a4640 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/README.txt @@ -0,0 +1,47 @@ +JAX-RS Swagger2Feature Demo +================= + +The demo shows a basic usage of Swagger 2.0 API documentation with REST based Web Services using +JAX-RS 2.0 (JSR-339) and path-based configuration. Swagger UI is available at: http://localhost:9000/ + +There are two versions of the API deployed under /v1/ and /v2/ base paths. The demo project demonstrates +the usage of path-based configuration for properly publishing Swagger 2.0 API documentation. + +Building and running the demo using Maven +--------------------------------------- + +From the base directory of this sample (i.e., where this README file is +located), the Maven pom.xml file can be used to build and run the demo. + + +Using either UNIX or Windows: + + mvn install + mvn -Pserver (from one command line window) + + +After the service is started, the Swagger API documents in JSON and YAML +are available at + + http://localhost:9000/v1/swagger.json + http://localhost:9000/v1/swagger.yaml + + http://localhost:9000/v2/swagger.json + http://localhost:9000/v2/swagger.yaml + +To view the Swagger document using Swagger-UI, use your Browser to +open the Swagger-UI page at + + http://localhost:9000/v1?url=swagger.json + http://localhost:9000/v2?url=swagger.json + +or + + http://localhost:9000/v1?url=swagger.yaml + http://localhost:9000/v2?url=swagger.yaml + + +To remove the target dir, run mvn clean". + + + http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/pom.xml ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/pom.xml b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/pom.xml new file mode 100644 index 0000000..c7f8932 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/pom.xml @@ -0,0 +1,151 @@ +<?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>jax_rs_description_swagger2_per_path_config</artifactId> + <name>JAX-RS Swagger2 Demo</name> + <description>JAX-RS Basic Demo</description> + <parent> + <groupId>org.apache.cxf.samples</groupId> + <artifactId>cxf-samples</artifactId> + <version>3.2.0-SNAPSHOT</version> + <relativePath>../..</relativePath> + </parent> + + <properties> + <cxf.version>${project.version}</cxf.version> + <httpclient.version>3.1</httpclient.version> + </properties> + + <profiles> + <profile> + <id>server</id> + <build> + <defaultGoal>test</defaultGoal> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <executions> + <execution> + <phase>test</phase> + <goals> + <goal>java</goal> + </goals> + <configuration> + <mainClass>demo.jaxrs.swagger.server.Server</mainClass> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <version>2.9</version> + <executions> + <execution> + <phase>generate-resources</phase> + <goals> + <goal>unpack</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>org.webjars</groupId> + <artifactId>swagger-ui</artifactId> + <version>2.1.0</version> + <overWrite>true</overWrite> + <outputDirectory>${project.build.directory}/classes</outputDirectory> + </artifactItem> + </artifactItems> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>io.swagger</groupId> + <artifactId>swagger-jaxrs</artifactId> + <exclusions> + <exclusion> + <groupId>javax.ws.rs</groupId> + <artifactId>jsr311-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.webjars</groupId> + <artifactId>swagger-ui</artifactId> + <version>2.1.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.jaxrs</groupId> + <artifactId>jackson-jaxrs-json-provider</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-transports-http</artifactId> + <version>3.2.0-SNAPSHOT</version> + </dependency> + <!-- This dependency is needed if you're using the Jetty container --> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-transports-http-jetty</artifactId> + <version>3.2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-frontend-jaxrs</artifactId> + <version>3.2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-rs-service-description-swagger</artifactId> + <version>3.2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>commons-httpclient</groupId> + <artifactId>commons-httpclient</artifactId> + </dependency> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/ApiOriginFilter.java ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/ApiOriginFilter.java b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/ApiOriginFilter.java new file mode 100644 index 0000000..43dd95d --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/ApiOriginFilter.java @@ -0,0 +1,45 @@ +/** + * 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 demo.jaxrs.swagger.server; + +import java.io.IOException; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.MultivaluedMap; + +/** + * This is a simple optional CORS filter used for this demo to make the resources accessible + * from other origins. You may omit using this filter or use CXF's advanced CORS filter + * org.apache.cxf.rs.security.cors.CrossOriginResourceSharingFilter + * included in cxf-rt-rs-security-cors if you need a more comprehensive accessibility rules. + */ +public class ApiOriginFilter implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + MultivaluedMap<String, Object> headers = responseContext.getHeaders(); + headers.add("Access-Control-Allow-Origin", "*"); + headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); + headers.add("Access-Control-Allow-Headers", "Content-Type"); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/Item.java ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/Item.java b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/Item.java new file mode 100644 index 0000000..1b5be9b --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/Item.java @@ -0,0 +1,49 @@ +/** + * 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 demo.jaxrs.swagger.server; + +public class Item { + private String name; + private String value; + + public Item() { + } + + public Item(final String name, final String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/Server.java ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/Server.java b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/Server.java new file mode 100644 index 0000000..b10ed6d --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/server/Server.java @@ -0,0 +1,93 @@ +/** + * 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 demo.jaxrs.swagger.server; + +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + +import org.apache.commons.lang3.StringUtils; +import org.apache.cxf.jaxrs.provider.MultipartProvider; +import org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet; +import org.apache.cxf.jaxrs.swagger.Swagger2Feature; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +public class Server { + + protected Server() throws Exception { + org.eclipse.jetty.server.Server server = new org.eclipse.jetty.server.Server(9000); + + // Configuring all static web resource + final ServletHolder staticHolder = new ServletHolder(new DefaultServlet()); + // Register and map the dispatcher servlet + final ServletContextHandler context = new ServletContextHandler(); + context.setContextPath("/"); + context.addServlet(staticHolder, "/*"); + context.setResourceBase( + getClass().getResource("/META-INF/resources/webjars/swagger-ui/2.1.0").toURI().toString()); + + final ServletHolder servletHolderV1 = new ServletHolder(new CXFNonSpringJaxrsServlet()); + context.addServlet(servletHolderV1, "/v1/*"); + servletHolderV1.setInitParameter("redirects-list", + "/ /index.html /.*[.]js /css/.* /images/.* lib/.* .*ico /fonts/.*"); + servletHolderV1.setInitParameter("redirect-servlet-name", staticHolder.getName()); + servletHolderV1.setInitParameter("redirect-attributes", "javax.servlet.include.request_uri"); + servletHolderV1.setInitParameter("jaxrs.serviceClasses", demo.jaxrs.swagger.v1.Sample.class.getName()); + servletHolderV1.setInitParameter("jaxrs.features", + Swagger2Feature.class.getName() + "(basePath=/v1 usePathBasedConfig=true)"); + servletHolderV1.setInitParameter("jaxrs.providers", StringUtils.join( + new String[] { + MultipartProvider.class.getName(), + JacksonJsonProvider.class.getName(), + ApiOriginFilter.class.getName() + }, ",") + ); + + final ServletHolder servletHolderV2 = new ServletHolder(new CXFNonSpringJaxrsServlet()); + context.addServlet(servletHolderV2, "/v2/*"); + servletHolderV2.setInitParameter("redirects-list", + "/ /index.html /.*[.]js /css/.* /images/.* lib/.* .*ico /fonts/.*"); + servletHolderV2.setInitParameter("redirect-servlet-name", staticHolder.getName()); + servletHolderV2.setInitParameter("redirect-attributes", "javax.servlet.include.request_uri"); + servletHolderV2.setInitParameter("jaxrs.serviceClasses", demo.jaxrs.swagger.v2.Sample.class.getName()); + servletHolderV2.setInitParameter("jaxrs.features", + Swagger2Feature.class.getName() + "(basePath=/v2 usePathBasedConfig=true)"); + servletHolderV2.setInitParameter("jaxrs.providers", StringUtils.join( + new String[] { + MultipartProvider.class.getName(), + JacksonJsonProvider.class.getName(), + ApiOriginFilter.class.getName() + }, ",") + ); + + server.setHandler(context); + server.start(); + server.join(); + } + + public static void main(String args[]) throws Exception { + new Server(); + System.out.println("Server ready..."); + + Thread.sleep(5 * 6000 * 1000); + System.out.println("Server exiting"); + System.exit(0); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/v1/Sample.java ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/v1/Sample.java b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/v1/Sample.java new file mode 100644 index 0000000..a18cff2 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/v1/Sample.java @@ -0,0 +1,141 @@ +/** + * 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 demo.jaxrs.swagger.v1; + +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import demo.jaxrs.swagger.server.Item; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; + +@Path("/sample") +@Api(value = "/v1/sample", description = "Sample JAX-RS service with Swagger documentation") +public class Sample { + private Map<String, Item> items; + + public Sample() { + items = Collections.synchronizedMap(new TreeMap<String, Item>(String.CASE_INSENSITIVE_ORDER)); + items.put("Item 1", new Item("Item 1 (v1)", "Value 1")); + items.put("Item 2", new Item("Item 2 (v1)", "Value 2")); + } + + + @Produces({ MediaType.APPLICATION_JSON }) + @GET + @ApiOperation( + value = "Get operation with Response and @Default value", + notes = "Get operation with Response and @Default value", + response = Item.class, + responseContainer = "List" + ) + public Response getItems( + @ApiParam(value = "Page to fetch", required = true) @QueryParam("page") @DefaultValue("1") int page) { + + return Response.ok(items.values()).build(); + } + + @Produces({ MediaType.APPLICATION_JSON }) + @Path("/{name}") + @GET + @ApiOperation( + value = "Get operation with type and headers", + notes = "Get operation with type and headers", + response = Item.class + ) + public Item getItem( + @ApiParam(value = "language", required = true) @HeaderParam("Accept-Language") final String language, + @ApiParam(value = "name", required = true) @PathParam("name") String name) { + return items.get(name); + } + + @Consumes({ MediaType.APPLICATION_JSON }) + @POST + @ApiOperation( + value = "Post operation with entity in a body", + notes = "Post operation with entity in a body", + response = Item.class + ) + public Response createItem( + @Context final UriInfo uriInfo, + @ApiParam(value = "item", required = true) final Item item) { + items.put(item.getName(), item); + return Response + .created(uriInfo.getBaseUriBuilder().path(item.getName()).build()) + .entity(item).build(); + } + + @Produces({ MediaType.APPLICATION_JSON }) + @Path("/{name}") + @PUT + @ApiOperation( + value = "Put operation with form parameter", + notes = "Put operation with form parameter", + response = Item.class + ) + public Item updateItem( + @ApiParam(value = "name", required = true) @PathParam("name") String name, + @ApiParam(value = "value", required = true) @FormParam("value") String value) { + Item item = new Item(name, value); + items.put(name, item); + return item; + } + + @Path("/{name}") + @DELETE + @ApiOperation( + value = "Delete operation with implicit header", + notes = "Delete operation with implicit header" + ) + @ApiImplicitParams( + @ApiImplicitParam( + name = "Accept-Language", + value = "language", + required = true, + dataType = "String", + paramType = "header" + ) + ) + public Response delete(@ApiParam(value = "name", required = true) @PathParam("name") String name) { + items.remove(name); + return Response.ok().build(); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/v2/Sample.java ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/v2/Sample.java b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/v2/Sample.java new file mode 100644 index 0000000..36ddc02 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/java/demo/jaxrs/swagger/v2/Sample.java @@ -0,0 +1,140 @@ +/** + * 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 demo.jaxrs.swagger.v2; + +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import demo.jaxrs.swagger.server.Item; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; + +@Path("/sample") +@Api(value = "/v2/sample", description = "Sample JAX-RS service with Swagger documentation") +public class Sample { + private Map<String, Item> items; + + public Sample() { + items = Collections.synchronizedMap(new TreeMap<String, Item>(String.CASE_INSENSITIVE_ORDER)); + items.put("Item 1", new Item("Item 1 (v2)", "Value 1")); + items.put("Item 2", new Item("Item 2 (v2)", "Value 2")); + } + + @Produces({ MediaType.APPLICATION_JSON }) + @GET + @ApiOperation( + value = "Get operation with Response and @Default value", + notes = "Get operation with Response and @Default value", + response = Item.class, + responseContainer = "List" + ) + public Response getItems( + @ApiParam(value = "Page to fetch", required = true) @QueryParam("page") @DefaultValue("1") int page) { + + return Response.ok(items.values()).build(); + } + + @Produces({ MediaType.APPLICATION_JSON }) + @Path("/{name}") + @GET + @ApiOperation( + value = "Get operation with type and headers", + notes = "Get operation with type and headers", + response = Item.class + ) + public Item getItem( + @ApiParam(value = "language", required = true) @HeaderParam("Accept-Language") final String language, + @ApiParam(value = "name", required = true) @PathParam("name") String name) { + return items.get(name); + } + + @Consumes({ MediaType.APPLICATION_JSON }) + @POST + @ApiOperation( + value = "Post operation with entity in a body", + notes = "Post operation with entity in a body", + response = Item.class + ) + public Response createItem( + @Context final UriInfo uriInfo, + @ApiParam(value = "item", required = true) final Item item) { + items.put(item.getName(), item); + return Response + .created(uriInfo.getBaseUriBuilder().path(item.getName()).build()) + .entity(item).build(); + } + + @Produces({ MediaType.APPLICATION_JSON }) + @Path("/{name}") + @PUT + @ApiOperation( + value = "Put operation with form parameter", + notes = "Put operation with form parameter", + response = Item.class + ) + public Item updateItem( + @ApiParam(value = "name", required = true) @PathParam("name") String name, + @ApiParam(value = "value", required = true) @FormParam("value") String value) { + Item item = new Item(name, value); + items.put(name, item); + return item; + } + + @Path("/{name}") + @DELETE + @ApiOperation( + value = "Delete operation with implicit header", + notes = "Delete operation with implicit header" + ) + @ApiImplicitParams( + @ApiImplicitParam( + name = "Accept-Language", + value = "language", + required = true, + dataType = "String", + paramType = "header" + ) + ) + public Response delete(@ApiParam(value = "name", required = true) @PathParam("name") String name) { + items.remove(name); + return Response.ok().build(); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/resources/META-INF/cxf/org.apache.cxf.Logger ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/resources/META-INF/cxf/org.apache.cxf.Logger b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/resources/META-INF/cxf/org.apache.cxf.Logger new file mode 100644 index 0000000..27dd788 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/resources/META-INF/cxf/org.apache.cxf.Logger @@ -0,0 +1 @@ +org.apache.cxf.common.logging.Slf4jLogger \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/resources/logback.xml ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/resources/logback.xml b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/resources/logback.xml new file mode 100644 index 0000000..0a3e031 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/description_swagger2_per_path_config/src/main/resources/logback.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration scan="true" scanPeriod="5 seconds"> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>[%level] %d{yyyy-MM-dd HH:mm:ss.SSS} %logger{36} - [%X] %msg%n</pattern> + </encoder> + </appender> + + <root level="INFO"> + <appender-ref ref="STDOUT" /> + </root> + + <logger category="com.wordnik.swagger" name="swagger"> + <level name="DEBUG"/> + </logger> +</configuration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/distribution/src/main/release/samples/pom.xml ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/pom.xml b/distribution/src/main/release/samples/pom.xml index ca874f3..687b99c 100644 --- a/distribution/src/main/release/samples/pom.xml +++ b/distribution/src/main/release/samples/pom.xml @@ -115,6 +115,7 @@ <module>jax_rs/tracing_htrace</module> <module>clustering/failover_jaxws_osgi</module> <module>clustering/failover_server</module> + <module>jax_rs/description_swagger2_per_path_config</module> <!-- These are removed from the build as they currently don't inherit the parent from http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/parent/pom.xml ---------------------------------------------------------------------- diff --git a/parent/pom.xml b/parent/pom.xml index 69af2f6..bf81458 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -154,7 +154,7 @@ <cxf.spring.ldap.version>1.3.1.RELEASE</cxf.spring.ldap.version> <cxf.spring.mock>spring-test</cxf.spring.mock> <cxf.swagger.version>1.3.13</cxf.swagger.version> - <cxf.swagger2.version>1.5.9</cxf.swagger2.version> + <cxf.swagger2.version>1.5.10</cxf.swagger2.version> <cxf.velocity.version>1.7</cxf.velocity.version> <cxf.woodstox.core.version>4.4.1</cxf.woodstox.core.version> <cxf.woodstox.stax2-api.version>3.1.4</cxf.woodstox.stax2-api.version> http://git-wip-us.apache.org/repos/asf/cxf/blob/3e30d889/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java ---------------------------------------------------------------------- diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java index 136bbee..763944c 100644 --- a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java +++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java @@ -22,15 +22,18 @@ import java.io.IOException; import java.net.URI; import java.net.URL; import java.util.ArrayList; +import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.regex.Pattern; +import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.ws.rs.GET; import javax.ws.rs.HttpMethod; @@ -54,6 +57,7 @@ import org.apache.cxf.annotations.Provider.Type; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.endpoint.Server; import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean; +import org.apache.cxf.jaxrs.ext.ContextProvider; import org.apache.cxf.jaxrs.ext.MessageContext; import org.apache.cxf.jaxrs.model.ApplicationInfo; import org.apache.cxf.jaxrs.model.ClassResourceInfo; @@ -62,21 +66,16 @@ import org.apache.cxf.jaxrs.model.doc.JavaDocProvider; import org.apache.cxf.jaxrs.provider.ServerProviderFactory; import org.apache.cxf.jaxrs.utils.InjectionUtils; import org.apache.cxf.jaxrs.utils.JAXRSUtils; +import org.apache.cxf.message.Message; import io.swagger.jaxrs.config.BeanConfig; import io.swagger.jaxrs.config.DefaultReaderConfig; import io.swagger.jaxrs.config.ReaderConfig; +import io.swagger.jaxrs.config.SwaggerContextService; import io.swagger.jaxrs.listing.ApiListingResource; @Provider(value = Type.Feature, scope = Scope.Server) public class Swagger2Feature extends AbstractSwaggerFeature { - - protected boolean dynamicBasePath; - - protected boolean replaceTags; - - protected DocumentationProvider javadocProvider; - private String host; private String[] schemes; @@ -91,6 +90,14 @@ public class Swagger2Feature extends AbstractSwaggerFeature { private String swaggerUiVersion; private Map<String, String> swaggerUiMediaTypes; + private boolean dynamicBasePath; + + private boolean replaceTags; + + private boolean usePathBasedConfig; + + private DocumentationProvider javadocProvider; + @Override protected void addSwaggerResource(Server server, Bus bus) { JAXRSServiceFactoryBean sfb = @@ -142,11 +149,17 @@ public class Swagger2Feature extends AbstractSwaggerFeature { } providers.add(new Swagger2Serializers(dynamicBasePath, replaceTags, javadocProvider, cris)); providers.add(new ReaderConfigFilter()); + + if (usePathBasedConfig) { + providers.add(new ServletConfigProvider()); + } + ((ServerProviderFactory) server.getEndpoint().get( ServerProviderFactory.class.getName())).setUserProviders(providers); BeanConfig beanConfig = new BeanConfig(); beanConfig.setResourcePackage(getResourcePackage()); + beanConfig.setUsePathBasedConfig(isUsePathBasedConfig()); beanConfig.setVersion(getVersion()); String basePath = getBasePath(); beanConfig.setBasePath(basePath); @@ -163,6 +176,14 @@ public class Swagger2Feature extends AbstractSwaggerFeature { beanConfig.setFilterClass(getFilterClass()); } + public boolean isUsePathBasedConfig() { + return usePathBasedConfig; + } + + public void setUsePathBasedConfig(boolean usePathBasedConfig) { + this.usePathBasedConfig = usePathBasedConfig; + } + public String getHost() { return host; } @@ -247,6 +268,42 @@ public class Swagger2Feature extends AbstractSwaggerFeature { this.swaggerUiMediaTypes = swaggerUiMediaTypes; } + @javax.ws.rs.ext.Provider + private class ServletConfigProvider implements ContextProvider<ServletConfig> { + public ServletConfig createContext(Message message) { + final ServletConfig sc = (ServletConfig)message.get("HTTP.CONFIG"); + + if (sc != null && sc.getInitParameter(SwaggerContextService.USE_PATH_BASED_CONFIG) == null) { + return new ServletConfig() { + @Override + public String getServletName() { + return sc.getServletName(); + } + + @Override + public ServletContext getServletContext() { + return sc.getServletContext(); + } + + @Override + public Enumeration<String> getInitParameterNames() { + return sc.getInitParameterNames(); + } + + @Override + public String getInitParameter(String name) { + if (Objects.equals(SwaggerContextService.USE_PATH_BASED_CONFIG, name)) { + return "true"; + } else { + return sc.getInitParameter(name); + } + } + }; + } + + return sc; + } + } @PreMatching protected static class SwaggerContainerRequestFilter extends ApiListingResource implements ContainerRequestFilter { @@ -265,6 +322,7 @@ public class Swagger2Feature extends AbstractSwaggerFeature { @Override public void filter(ContainerRequestContext requestContext) throws IOException { UriInfo ui = mc.getUriInfo(); + List<MediaType> mediaTypes = mc.getHttpHeaders().getAcceptableMediaTypes(); Response response = null;
