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 2016/07/11 00:14:09 UTC
[04/33] cxf git commit: [CXF-6760] Adding missing resources
[CXF-6760] Adding missing resources
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/636252c2
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/636252c2
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/636252c2
Branch: refs/heads/master-jaxrs-2.1
Commit: 636252c2ac66648fc5221ccdb71ebafde38feff6
Parents: 21031e3
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Mon Jul 4 15:01:25 2016 +0100
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Mon Jul 4 15:01:25 2016 +0100
----------------------------------------------------------------------
.../jaxrs/model/doc/DocumentationProvider.java | 29 ++
.../cxf/jaxrs/model/doc/JavaDocProvider.java | 380 +++++++++++++++++++
.../jaxrs/model/doc/JavaDocProviderTest.java | 107 ++++++
.../cxf/jaxrs/model/wadl/petstore/PetStore.java | 102 +++++
.../resources/javadocs/pet-store-javadoc16.jar | Bin 0 -> 3569 bytes
.../resources/javadocs/pet-store-javadoc17.jar | Bin 0 -> 3601 bytes
.../resources/javadocs/pet-store-javadoc18.jar | Bin 0 -> 3873 bytes
.../jaxrs/swagger/AbstractSwaggerFeature.java | 191 ++++++++++
.../cxf/jaxrs/swagger/JaxRs2Extension.java | 225 +++++++++++
.../cxf/jaxrs/swagger/MatrixParameter.java | 28 ++
.../cxf/jaxrs/swagger/Swagger2Feature.java | 259 +++++++++++++
.../cxf/jaxrs/swagger/Swagger2Serializers.java | 164 ++++++++
.../cxf/jaxrs/swagger/SwaggerFeature.java | 115 ++++++
.../apache/cxf/jaxrs/swagger/SwaggerUtils.java | 233 ++++++++++++
.../io.swagger.jaxrs.ext.SwaggerExtension | 1 +
.../cxf/jaxrs/swagger/Swagger2FeatureTest.java | 53 +++
.../cxf/jaxrs/swagger/SwaggerFeatureTest.java | 45 +++
.../cxf/jaxrs/swagger/SwaggerUtilsTest.java | 74 ++++
.../src/test/resources/swagger12.json | 27 ++
.../src/test/resources/swagger20.json | 44 +++
20 files changed, 2077 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/doc/DocumentationProvider.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/doc/DocumentationProvider.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/doc/DocumentationProvider.java
new file mode 100644
index 0000000..dff4fd6
--- /dev/null
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/doc/DocumentationProvider.java
@@ -0,0 +1,29 @@
+/**
+ * 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.model.doc;
+
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+
+public interface DocumentationProvider {
+ String getClassDoc(ClassResourceInfo cri);
+ String getMethodDoc(OperationResourceInfo ori);
+ String getMethodResponseDoc(OperationResourceInfo ori);
+ String getMethodParameterDoc(OperationResourceInfo ori, int paramIndex);
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/doc/JavaDocProvider.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/doc/JavaDocProvider.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/doc/JavaDocProvider.java
new file mode 100644
index 0000000..5e702fe
--- /dev/null
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/doc/JavaDocProvider.java
@@ -0,0 +1,380 @@
+/**
+ * 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.model.doc;
+
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.ws.rs.Path;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+
+public class JavaDocProvider implements DocumentationProvider {
+ public static final double JAVA_VERSION = getVersion();
+ public static final double JAVA_VERSION_16 = 1.6D;
+ public static final double JAVA_VERSION_17 = 1.7D;
+ public static final double JAVA_VERSION_18 = 1.8D;
+
+ private ClassLoader javaDocLoader;
+ private final ConcurrentHashMap<String, ClassDocs> docs = new ConcurrentHashMap<>();
+ private double javaDocsBuiltByVersion = JAVA_VERSION;
+
+ public JavaDocProvider(URL... javaDocUrls) {
+ if (javaDocUrls == null) {
+ throw new IllegalArgumentException("URL are null");
+ }
+
+ javaDocLoader = new URLClassLoader(javaDocUrls);
+ }
+
+ public JavaDocProvider(String path) throws Exception {
+ this(BusFactory.getDefaultBus(), path);
+ }
+
+ public JavaDocProvider(String... paths) throws Exception {
+ this(BusFactory.getDefaultBus(), paths == null ? null : paths);
+ }
+
+ public JavaDocProvider(Bus bus, String... paths) throws Exception {
+ if (paths == null) {
+ throw new IllegalArgumentException("paths are null");
+ }
+
+ URL[] javaDocUrls = new URL[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ javaDocUrls[i] = ResourceUtils.getResourceURL(paths[i], bus);
+ }
+ javaDocLoader = new URLClassLoader(javaDocUrls);
+ }
+
+ private static double getVersion() {
+ String version = System.getProperty("java.version");
+ try {
+ return Double.parseDouble(version.substring(0, 3));
+ } catch (Exception ex) {
+ return JAVA_VERSION_16;
+ }
+ }
+
+ @Override
+ public String getClassDoc(ClassResourceInfo cri) {
+ try {
+ ClassDocs doc = getClassDocInternal(cri.getServiceClass());
+ if (doc == null) {
+ return null;
+ }
+ return doc.getClassInfo();
+ } catch (Exception ex) {
+ // ignore
+ }
+ return null;
+ }
+
+ @Override
+ public String getMethodDoc(OperationResourceInfo ori) {
+ try {
+ MethodDocs doc = getOperationDocInternal(ori);
+ if (doc == null) {
+ return null;
+ }
+ return doc.getMethodInfo();
+ } catch (Exception ex) {
+ // ignore
+ }
+ return null;
+ }
+
+ @Override
+ public String getMethodResponseDoc(OperationResourceInfo ori) {
+ try {
+ MethodDocs doc = getOperationDocInternal(ori);
+ if (doc == null) {
+ return null;
+ }
+ return doc.getResponseInfo();
+ } catch (Exception ex) {
+ // ignore
+ }
+ return null;
+ }
+
+ @Override
+ public String getMethodParameterDoc(OperationResourceInfo ori, int paramIndex) {
+ try {
+ MethodDocs doc = getOperationDocInternal(ori);
+ if (doc == null) {
+ return null;
+ }
+ List<String> params = doc.getParamInfo();
+ if (paramIndex < params.size()) {
+ return params.get(paramIndex);
+ } else {
+ return null;
+ }
+ } catch (Exception ex) {
+ // ignore
+ }
+ return null;
+ }
+
+ private Class<?> getPathAnnotatedClass(Class<?> cls) {
+ if (cls.getAnnotation(Path.class) != null) {
+ return cls;
+ }
+ if (cls.getSuperclass() != null && cls.getSuperclass().getAnnotation(Path.class) != null) {
+ return cls.getSuperclass();
+ }
+ for (Class<?> i : cls.getInterfaces()) {
+ if (i.getAnnotation(Path.class) != null) {
+ return i;
+ }
+ }
+ return cls;
+ }
+
+ private ClassDocs getClassDocInternal(Class<?> cls) throws Exception {
+ Class<?> annotatedClass = getPathAnnotatedClass(cls);
+ String resource = annotatedClass.getName().replace(".", "/") + ".html";
+ ClassDocs classDocs = docs.get(resource);
+ if (classDocs == null) {
+ InputStream resourceStream = javaDocLoader.getResourceAsStream(resource);
+ if (resourceStream != null) {
+ String doc = IOUtils.readStringFromStream(resourceStream);
+
+ String qualifier = annotatedClass.isInterface() ? "Interface" : "Class";
+ String classMarker = qualifier + " " + annotatedClass.getSimpleName();
+ int index = doc.indexOf(classMarker);
+ if (index != -1) {
+ String classInfoTag = getClassInfoTag();
+ String classInfo = getJavaDocText(doc, classInfoTag,
+ "Method Summary", index + classMarker.length());
+ classDocs = new ClassDocs(doc, classInfo);
+ docs.putIfAbsent(resource, classDocs);
+ }
+ }
+ }
+ return classDocs;
+ }
+
+
+ private MethodDocs getOperationDocInternal(OperationResourceInfo ori) throws Exception {
+ Method method = ori.getAnnotatedMethod() == null
+ ? ori.getMethodToInvoke()
+ : ori.getAnnotatedMethod();
+ ClassDocs classDoc = getClassDocInternal(method.getDeclaringClass());
+ if (classDoc == null) {
+ return null;
+ }
+ MethodDocs mDocs = classDoc.getMethodDocs(method);
+ if (mDocs == null) {
+ String operLink = getOperLink();
+ String operMarker = operLink + method.getName() + getOperationMarkerOpen();
+
+ int operMarkerIndex = classDoc.getClassDoc().indexOf(operMarker);
+ while (operMarkerIndex != -1) {
+ int startOfOpSigIndex = operMarkerIndex + operMarker.length();
+ int endOfOpSigIndex = classDoc.getClassDoc().indexOf(getOperationMarkerClose(),
+ startOfOpSigIndex);
+ int paramLen = method.getParameterTypes().length;
+ if (endOfOpSigIndex == startOfOpSigIndex && paramLen == 0) {
+ break;
+ } else if (endOfOpSigIndex > startOfOpSigIndex + 1) {
+ String paramSequence = classDoc.getClassDoc().substring(operMarkerIndex, endOfOpSigIndex);
+ if (paramSequence.startsWith(operMarker)) {
+ paramSequence = paramSequence.substring(operMarker.length());
+ String[] opBits = paramSequence.split(getOperationParamSeparator());
+ if (opBits.length == paramLen) {
+ break;
+ }
+ }
+ }
+ operMarkerIndex = classDoc.getClassDoc().indexOf(operMarker,
+ operMarkerIndex + operMarker.length());
+ }
+
+ if (operMarkerIndex == -1) {
+ return null;
+ }
+
+ String operDoc = classDoc.getClassDoc().substring(operMarkerIndex + operMarker.length());
+ String operInfoTag = getOperInfoTag();
+ String operInfo = getJavaDocText(operDoc, operInfoTag, operLink, 0);
+ String responseInfo = null;
+ List<String> paramDocs = new LinkedList<>();
+ if (!StringUtils.isEmpty(operInfo)) {
+ int returnsIndex = operDoc.indexOf("Returns:", operLink.length());
+ int nextOpIndex = operDoc.indexOf(operLink);
+ if (returnsIndex != -1 && (nextOpIndex > returnsIndex || nextOpIndex == -1)) {
+ responseInfo = getJavaDocText(operDoc, getResponseMarker(), operLink, returnsIndex + 8);
+ }
+
+ int paramIndex = operDoc.indexOf("Parameters:");
+ if (paramIndex != -1 && (nextOpIndex == -1 || paramIndex < nextOpIndex)) {
+ String paramString = returnsIndex == -1 ? operDoc.substring(paramIndex)
+ : operDoc.substring(paramIndex, returnsIndex);
+
+ String codeTag = getCodeTag();
+
+ int codeIndex = paramString.indexOf(codeTag);
+ while (codeIndex != -1) {
+ int next = paramString.indexOf('<', codeIndex + 7);
+ if (next == -1) {
+ next = paramString.length();
+ }
+ String param = paramString.substring(codeIndex + 7, next).trim();
+ if (param.startsWith("-")) {
+ param = param.substring(1).trim();
+ }
+ paramDocs.add(param);
+ if (next == paramString.length()) {
+ break;
+ } else {
+ codeIndex = next + 1;
+ }
+ codeIndex = paramString.indexOf(codeTag, codeIndex);
+ }
+
+ }
+ }
+ mDocs = new MethodDocs(operInfo, paramDocs, responseInfo);
+ classDoc.addMethodDocs(method, mDocs);
+ }
+
+ return mDocs;
+ }
+
+
+
+ private String getJavaDocText(String doc, String tag, String notAfterTag, int index) {
+ int tagIndex = doc.indexOf(tag, index);
+ if (tagIndex != -1) {
+ int notAfterIndex = doc.indexOf(notAfterTag, index);
+ if (notAfterIndex == -1 || notAfterIndex > tagIndex) {
+ int nextIndex = doc.indexOf('<', tagIndex + tag.length());
+ if (nextIndex != -1) {
+ return doc.substring(tagIndex + tag.length(), nextIndex).trim();
+ }
+ }
+ }
+ return null;
+ }
+
+ protected String getClassInfoTag() {
+ if (javaDocsBuiltByVersion == JAVA_VERSION_16) {
+ return "<P>";
+ } else {
+ return "<div class=\"block\">";
+ }
+ }
+ protected String getOperInfoTag() {
+ if (javaDocsBuiltByVersion == JAVA_VERSION_16) {
+ return "<DD>";
+ } else {
+ return "<div class=\"block\">";
+ }
+ }
+ protected String getOperLink() {
+ String operLink = "<A NAME=\"";
+ return javaDocsBuiltByVersion == JAVA_VERSION_16 ? operLink : operLink.toLowerCase();
+ }
+
+ protected String getResponseMarker() {
+ String tag = "<DD>";
+ return javaDocsBuiltByVersion == JAVA_VERSION_16 ? tag : tag.toLowerCase();
+ }
+
+ protected String getCodeTag() {
+ String tag = "</CODE>";
+ return javaDocsBuiltByVersion == JAVA_VERSION_16 ? tag : tag.toLowerCase();
+ }
+
+ protected String getOperationMarkerOpen() {
+ return javaDocsBuiltByVersion == JAVA_VERSION_18 ? "-" : "(";
+ }
+ protected String getOperationMarkerClose() {
+ return javaDocsBuiltByVersion == JAVA_VERSION_18 ? "-\"" : ")";
+ }
+ protected String getOperationParamSeparator() {
+ return javaDocsBuiltByVersion == JAVA_VERSION_18 ? "-" : ",";
+ }
+ public void setJavaDocsBuiltByVersion(String version) {
+ javaDocsBuiltByVersion = Double.valueOf(version);
+ }
+
+ private static class ClassDocs {
+ private final String classDoc;
+ private final String classInfo;
+ private final ConcurrentHashMap<Method, MethodDocs> mdocs = new ConcurrentHashMap<>();
+ ClassDocs(String classDoc, String classInfo) {
+ this.classDoc = classDoc;
+ this.classInfo = classInfo;
+ }
+
+ public String getClassDoc() {
+ return classDoc;
+ }
+
+ public String getClassInfo() {
+ return classInfo;
+ }
+
+ public MethodDocs getMethodDocs(Method method) {
+ return mdocs.get(method);
+ }
+
+ public void addMethodDocs(Method method, MethodDocs doc) {
+ mdocs.putIfAbsent(method, doc);
+ }
+ }
+
+ private static class MethodDocs {
+ private final String methodInfo;
+ private final List<String> paramInfo;
+ private final String responseInfo;
+ MethodDocs(String methodInfo, List<String> paramInfo, String responseInfo) {
+ this.methodInfo = methodInfo;
+ this.paramInfo = paramInfo;
+ this.responseInfo = responseInfo;
+ }
+
+ public String getMethodInfo() {
+ return methodInfo;
+ }
+
+ public List<String> getParamInfo() {
+ return paramInfo;
+ }
+
+ public String getResponseInfo() {
+ return responseInfo;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/doc/JavaDocProviderTest.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/doc/JavaDocProviderTest.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/doc/JavaDocProviderTest.java
new file mode 100644
index 0000000..94319e4
--- /dev/null
+++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/doc/JavaDocProviderTest.java
@@ -0,0 +1,107 @@
+/**
+ * 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.model.doc;
+
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.model.wadl.petstore.PetStore;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JavaDocProviderTest extends Assert {
+
+ @Test
+ public void testJava6Docs() throws Exception {
+ doTestJavaDocs("classpath:/javadocs/pet-store-javadoc16.jar", "1.6");
+ }
+
+ @Test
+ public void testJava7Docs() throws Exception {
+ doTestJavaDocs("classpath:/javadocs/pet-store-javadoc17.jar", "1.7");
+ }
+ @Test
+ public void testJava8Docs() throws Exception {
+ doTestJavaDocs("classpath:/javadocs/pet-store-javadoc18.jar", "1.8");
+ }
+
+ private void doTestJavaDocs(String path, String version) throws Exception {
+ JavaDocProvider p = new JavaDocProvider(path);
+ p.setJavaDocsBuiltByVersion(version);
+ ClassResourceInfo cri =
+ ResourceUtils.createClassResourceInfo(PetStore.class, PetStore.class, true, true);
+ String classDoc = p.getClassDoc(cri);
+ assertEquals("The Pet Store", classDoc);
+
+ boolean getStatus1Tested = false;
+ boolean getStatus2Tested = false;
+ boolean getStatus3Tested = false;
+ boolean noDocsTested = false;
+ for (OperationResourceInfo ori : cri.getMethodDispatcher().getOperationResourceInfos()) {
+ if ("getStatus1Param".equals(ori.getMethodToInvoke().getName())) {
+ testGetStatus1JavaDocs(p, ori);
+ getStatus1Tested = true;
+ } else if ("getStatus2Params".equals(ori.getMethodToInvoke().getName())) {
+ testGetStatus2JavaDocs(p, ori);
+ getStatus2Tested = true;
+ } else if ("getStatus3Params".equals(ori.getMethodToInvoke().getName())) {
+ testGetStatus3JavaDocs(p, ori);
+ getStatus3Tested = true;
+ } else if ("getBaseStatus".equals(ori.getMethodToInvoke().getName())) {
+ testOperWithNoJavaDocs(p, ori);
+ noDocsTested = true;
+ }
+ }
+ assertTrue(getStatus1Tested);
+ assertTrue(getStatus2Tested);
+ assertTrue(getStatus3Tested);
+ assertTrue(noDocsTested);
+ assertTrue(true);
+ }
+
+ private void testOperWithNoJavaDocs(JavaDocProvider p, OperationResourceInfo ori) {
+ assertEquals(0, ori.getParameters().size());
+ assertEquals("Return Pet Status with no params", p.getMethodDoc(ori));
+ assertEquals("status", p.getMethodResponseDoc(ori));
+ }
+
+ private void testGetStatus1JavaDocs(JavaDocProvider p, OperationResourceInfo ori) {
+ assertEquals("Return Pet Status With 1 Param", p.getMethodDoc(ori));
+ assertEquals(1, ori.getParameters().size());
+ assertEquals("status", p.getMethodResponseDoc(ori));
+ assertEquals("the pet id", p.getMethodParameterDoc(ori, 0));
+ }
+ private void testGetStatus2JavaDocs(JavaDocProvider p, OperationResourceInfo ori) {
+ assertEquals("Return Pet Status with 2 params", p.getMethodDoc(ori));
+ assertEquals(2, ori.getParameters().size());
+ assertEquals("status", p.getMethodResponseDoc(ori));
+ assertEquals("the pet id", p.getMethodParameterDoc(ori, 0));
+ assertEquals("the query", p.getMethodParameterDoc(ori, 1));
+ }
+ private void testGetStatus3JavaDocs(JavaDocProvider p, OperationResourceInfo ori) {
+ assertEquals("Return Pet Status With 3 Params", p.getMethodDoc(ori));
+ assertEquals(3, ori.getParameters().size());
+ assertEquals("status", p.getMethodResponseDoc(ori));
+ assertEquals("the pet id", p.getMethodParameterDoc(ori, 0));
+ assertEquals("the query", p.getMethodParameterDoc(ori, 1));
+ assertEquals("the query2", p.getMethodParameterDoc(ori, 2));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java
new file mode 100644
index 0000000..356e702
--- /dev/null
+++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java
@@ -0,0 +1,102 @@
+/**
+ * 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.model.wadl.petstore;
+
+import javax.ws.rs.GET;
+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.Response;
+
+/**
+ * The Pet Store
+ */
+@Path("/")
+public class PetStore {
+
+ public static final String CLOSED = "The Pet Store is closed";
+
+ public PetStore() {
+ }
+
+ @GET
+ @Produces("text/plain")
+ /**
+ * Return Pet Status with no params
+ *
+ * @return status
+ * @throws Exception
+ */
+ public Response getBaseStatus() throws Exception {
+
+ return Response.ok(CLOSED).build();
+ }
+
+ /**
+ * Return Pet Status with 2 params
+ * @param petId the pet id
+ * @param query the query
+ * @return status
+ * @throws Exception
+ */
+ @GET
+ @Path("/petstore/pets/{petId}/")
+ @Produces("text/xml")
+ public Response getStatus2Params(@PathParam("petId") String petId,
+ @QueryParam("query") String query) throws Exception {
+
+ return Response.ok(CLOSED).build();
+ }
+
+ /**
+ * Return Pet Status With 1 Param
+ * @param petId the pet id
+ * @return status
+ * @throws Exception
+ */
+ @GET
+ @Path("/petstore/pets/id/{petId}/")
+ @Produces("text/xml")
+ public Response getStatus1Param(@PathParam("petId") String petId) throws Exception {
+
+ return Response.ok(CLOSED).build();
+ }
+
+
+ /**
+ * Return Pet Status With 3 Params
+ * @param petId the pet id
+ * @param query the query
+ * @param query2 the query2
+ * @return status
+ * @throws Exception
+ */
+ @GET
+ @Path("/petstore/pets/{petId}/")
+ @Produces("text/xml")
+ public Response getStatus3Params(@PathParam("petId") String petId,
+ @QueryParam("query") String query,
+ @QueryParam("query2") String query2) throws Exception {
+
+ return Response.ok(CLOSED).build();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc16.jar
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc16.jar b/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc16.jar
new file mode 100644
index 0000000..b7f2cb6
Binary files /dev/null and b/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc16.jar differ
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc17.jar
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc17.jar b/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc17.jar
new file mode 100644
index 0000000..d49a58d
Binary files /dev/null and b/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc17.jar differ
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc18.jar
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc18.jar b/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc18.jar
new file mode 100644
index 0000000..24a8c63
Binary files /dev/null and b/rt/frontend/jaxrs/src/test/resources/javadocs/pet-store-javadoc18.jar differ
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/AbstractSwaggerFeature.java
----------------------------------------------------------------------
diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/AbstractSwaggerFeature.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/AbstractSwaggerFeature.java
new file mode 100644
index 0000000..c933b30
--- /dev/null
+++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/AbstractSwaggerFeature.java
@@ -0,0 +1,191 @@
+/**
+ * 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.swagger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.util.PackageUtils;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+
+public abstract class AbstractSwaggerFeature extends AbstractFeature {
+
+ private static final boolean SWAGGER_JAXRS_AVAILABLE;
+
+ static {
+ SWAGGER_JAXRS_AVAILABLE = isSwaggerJaxRsAvailable();
+ }
+
+ protected boolean scan = true;
+ protected boolean runAsFilter;
+ private boolean activateOnlyIfJaxrsSupported;
+ private String resourcePackage;
+ private String version = "1.0.0";
+ // depending on swagger version basePath is set differently
+ private String basePath;
+ private String title = "Sample REST Application";
+ private String description = "The Application";
+ private String contact = "users@cxf.apache.org";
+ private String license = "Apache 2.0 License";
+ private String licenseUrl = "http://www.apache.org/licenses/LICENSE-2.0.html";
+ private String termsOfServiceUrl;
+ private String filterClass;
+
+ private static boolean isSwaggerJaxRsAvailable() {
+ try {
+ Class.forName("io.swagger.jaxrs.DefaultParameterExtension");
+ return true;
+ } catch (Throwable ex) {
+ return false;
+ }
+ }
+
+ @Override
+ public void initialize(Server server, Bus bus) {
+ if (!activateOnlyIfJaxrsSupported || SWAGGER_JAXRS_AVAILABLE) {
+ calculateDefaultResourcePackage(server);
+ calculateDefaultBasePath(server);
+ addSwaggerResource(server);
+
+ initializeProvider(server.getEndpoint(), bus);
+ bus.setProperty("swagger.service.descrition.available", "true");
+ }
+ }
+
+ protected abstract void addSwaggerResource(Server server);
+
+ protected abstract void setBasePathByAddress(String address);
+
+ private void calculateDefaultResourcePackage(Server server) {
+ if (!StringUtils.isEmpty(getResourcePackage())) {
+ return;
+ }
+ JAXRSServiceFactoryBean serviceFactoryBean =
+ (JAXRSServiceFactoryBean)server.getEndpoint().get(JAXRSServiceFactoryBean.class.getName());
+ List<ClassResourceInfo> resourceInfos = serviceFactoryBean.getClassResourceInfo();
+
+ if (resourceInfos.size() == 1) {
+ setResourcePackage(resourceInfos.get(0).getServiceClass().getPackage().getName());
+ } else {
+ List<Class<?>> serviceClasses = new ArrayList<Class<?>>(resourceInfos.size());
+ for (ClassResourceInfo cri : resourceInfos) {
+ serviceClasses.add(cri.getServiceClass());
+ }
+ String sharedPackage = PackageUtils.getSharedPackageName(serviceClasses);
+ if (!StringUtils.isEmpty(sharedPackage)) {
+ setResourcePackage(sharedPackage);
+ }
+ }
+ }
+
+ private void calculateDefaultBasePath(Server server) {
+ if (getBasePath() == null || getBasePath().length() == 0) {
+ String address = server.getEndpoint().getEndpointInfo().getAddress();
+ setBasePathByAddress(address);
+ }
+ }
+
+ public String getResourcePackage() {
+ return resourcePackage;
+ }
+ public void setResourcePackage(String resourcePackage) {
+ this.resourcePackage = resourcePackage;
+ }
+ public String getVersion() {
+ return version;
+ }
+ public void setVersion(String version) {
+ this.version = version;
+ }
+ public String getBasePath() {
+ return basePath;
+ }
+ public void setBasePath(String basePath) {
+ this.basePath = basePath;
+ }
+ 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 getContact() {
+ return contact;
+ }
+ public void setContact(String contact) {
+ this.contact = contact;
+ }
+ 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 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 boolean isRunAsFilter() {
+ return runAsFilter;
+ }
+ public void setRunAsFilter(boolean runAsFilter) {
+ this.runAsFilter = runAsFilter;
+ }
+
+ public boolean isActivateOnlyIfJaxrsSupported() {
+ return activateOnlyIfJaxrsSupported;
+ }
+
+ public void setActivateOnlyIfJaxrsSupported(boolean activateOnlyIfJaxrsSupported) {
+ this.activateOnlyIfJaxrsSupported = activateOnlyIfJaxrsSupported;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/JaxRs2Extension.java
----------------------------------------------------------------------
diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/JaxRs2Extension.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/JaxRs2Extension.java
new file mode 100644
index 0000000..87e0cf2
--- /dev/null
+++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/JaxRs2Extension.java
@@ -0,0 +1,225 @@
+/**
+ * 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.swagger;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.validation.constraints.DecimalMax;
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import javax.ws.rs.BeanParam;
+import javax.ws.rs.MatrixParam;
+
+import com.fasterxml.jackson.databind.BeanDescription;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.introspect.AnnotatedField;
+import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
+import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
+
+import io.swagger.converter.ModelConverters;
+import io.swagger.jaxrs.ext.AbstractSwaggerExtension;
+import io.swagger.jaxrs.ext.SwaggerExtension;
+import io.swagger.jaxrs.ext.SwaggerExtensions;
+import io.swagger.models.parameters.AbstractSerializableParameter;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.Property;
+import io.swagger.models.properties.RefProperty;
+import io.swagger.models.properties.StringProperty;
+import io.swagger.util.Json;
+import io.swagger.util.ParameterProcessor;
+
+public class JaxRs2Extension extends AbstractSwaggerExtension {
+
+ private final ObjectMapper mapper = Json.mapper();
+
+ @Override
+ public List<Parameter> extractParameters(
+ final List<Annotation> annotations,
+ final Type type,
+ final Set<Type> typesToSkip,
+ final Iterator<SwaggerExtension> chain) {
+
+ if (shouldIgnoreType(type, typesToSkip)) {
+ return new ArrayList<>();
+ }
+
+ List<Parameter> parameters = new ArrayList<>();
+ for (Annotation annotation : annotations) {
+ if (annotation instanceof MatrixParam) {
+ MatrixParam param = (MatrixParam) annotation;
+ MatrixParameter mp = new MatrixParameter().name(param.value());
+
+ Property schema = createProperty(type);
+ if (schema != null) {
+ mp.setProperty(schema);
+ }
+ applyBeanValidatorAnnotations(mp, annotations);
+ parameters.add(mp);
+ } else if (annotation instanceof BeanParam) {
+ // Use Jackson's logic for processing Beans
+ final BeanDescription beanDesc = mapper.getSerializationConfig().introspect(constructType(type));
+ final List<BeanPropertyDefinition> properties = beanDesc.findProperties();
+
+ for (final BeanPropertyDefinition propDef : properties) {
+ final AnnotatedField field = propDef.getField();
+ final AnnotatedMethod setter = propDef.getSetter();
+ final List<Annotation> paramAnnotations = new ArrayList<>();
+ final Iterator<SwaggerExtension> extensions = SwaggerExtensions.chain();
+ Type paramType = null;
+
+ // Gather the field's details
+ if (field != null) {
+ paramType = field.getGenericType();
+
+ for (final Annotation fieldAnnotation : field.annotations()) {
+ if (!paramAnnotations.contains(fieldAnnotation)) {
+ paramAnnotations.add(fieldAnnotation);
+ }
+ }
+ }
+
+ // Gather the setter's details but only the ones we need
+ if (setter != null) {
+ // Do not set the param class/type from the setter if the values are already identified
+ if (paramType == null && setter.getGenericParameterTypes() != null) {
+ paramType = setter.getGenericParameterTypes()[0];
+ }
+
+ for (final Annotation fieldAnnotation : setter.annotations()) {
+ if (!paramAnnotations.contains(fieldAnnotation)) {
+ paramAnnotations.add(fieldAnnotation);
+ }
+ }
+ }
+
+ // Re-process all Bean fields and let the default swagger-jaxrs processor do its thing
+ List<Parameter> extracted =
+ extensions.next().extractParameters(paramAnnotations, paramType, typesToSkip, extensions);
+
+ // since downstream processors won't know how to introspect @BeanParam, process here
+ for (Parameter param : extracted) {
+ if (ParameterProcessor.applyAnnotations(null, param, paramType, paramAnnotations) != null) {
+ applyBeanValidatorAnnotations(param, paramAnnotations);
+ parameters.add(param);
+ }
+ }
+ }
+ }
+ }
+
+ // Only call down to the other items in the chain if no parameters were produced
+ if (parameters.isEmpty()) {
+ parameters = super.extractParameters(annotations, type, typesToSkip, chain);
+ }
+
+ return parameters;
+ }
+
+ private Property createProperty(final Type type) {
+ return enforcePrimitive(ModelConverters.getInstance().readAsProperty(type), 0);
+ }
+
+ private Property enforcePrimitive(final Property in, final int level) {
+ if (in instanceof RefProperty) {
+ return new StringProperty();
+ }
+ if (in instanceof ArrayProperty) {
+ if (level == 0) {
+ final ArrayProperty array = (ArrayProperty) in;
+ array.setItems(enforcePrimitive(array.getItems(), level + 1));
+ } else {
+ return new StringProperty();
+ }
+ }
+ return in;
+ }
+
+ /**
+ * This is essentially a duplicate of {@link io.swagger.jackson.ModelResolver.applyBeanValidatorAnnotations}.
+ *
+ * @param parameter
+ * @param annotations
+ */
+ private void applyBeanValidatorAnnotations(final Parameter parameter, final List<Annotation> annotations) {
+ Map<String, Annotation> annos = new HashMap<>();
+ if (annotations != null) {
+ for (Annotation annotation : annotations) {
+ annos.put(annotation.annotationType().getName(), annotation);
+ }
+ }
+
+ if (annos.containsKey(NotNull.class.getName())) {
+ parameter.setRequired(true);
+ }
+
+ if (parameter instanceof AbstractSerializableParameter) {
+ AbstractSerializableParameter<?> serializable = (AbstractSerializableParameter<?>) parameter;
+
+ if (annos.containsKey(Min.class.getName())) {
+ Min min = (Min) annos.get(Min.class.getName());
+ serializable.setMinimum(new Double(min.value()));
+ }
+ if (annos.containsKey(Max.class.getName())) {
+ Max max = (Max) annos.get(Max.class.getName());
+ serializable.setMaximum(new Double(max.value()));
+ }
+ if (annos.containsKey(Size.class.getName())) {
+ Size size = (Size) annos.get(Size.class.getName());
+
+ serializable.setMinimum(new Double(size.min()));
+ serializable.setMaximum(new Double(size.max()));
+
+ serializable.setMinItems(size.min());
+ serializable.setMaxItems(size.max());
+ }
+ if (annos.containsKey(DecimalMin.class.getName())) {
+ DecimalMin min = (DecimalMin) annos.get(DecimalMin.class.getName());
+ if (min.inclusive()) {
+ serializable.setMinimum(new Double(min.value()));
+ } else {
+ serializable.setExclusiveMinimum(!min.inclusive());
+ }
+ }
+ if (annos.containsKey(DecimalMax.class.getName())) {
+ DecimalMax max = (DecimalMax) annos.get(DecimalMax.class.getName());
+ if (max.inclusive()) {
+ serializable.setMaximum(new Double(max.value()));
+ } else {
+ serializable.setExclusiveMaximum(!max.inclusive());
+ }
+ }
+ if (annos.containsKey(Pattern.class.getName())) {
+ Pattern pattern = (Pattern) annos.get(Pattern.class.getName());
+ serializable.setPattern(pattern.regexp());
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/MatrixParameter.java
----------------------------------------------------------------------
diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/MatrixParameter.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/MatrixParameter.java
new file mode 100644
index 0000000..f1472c2
--- /dev/null
+++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/MatrixParameter.java
@@ -0,0 +1,28 @@
+/**
+ * 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.swagger;
+
+import io.swagger.models.parameters.AbstractSerializableParameter;
+
+public class MatrixParameter extends AbstractSerializableParameter<MatrixParameter> {
+
+ public MatrixParameter() {
+ super.setIn("matrix");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/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
new file mode 100644
index 0000000..bc9102f
--- /dev/null
+++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java
@@ -0,0 +1,259 @@
+/**
+ * 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.swagger;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.PreMatching;
+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 org.apache.cxf.annotations.Provider;
+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.MessageContext;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.doc.DocumentationProvider;
+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 io.swagger.jaxrs.config.BeanConfig;
+import io.swagger.jaxrs.config.DefaultReaderConfig;
+import io.swagger.jaxrs.config.ReaderConfig;
+import io.swagger.jaxrs.listing.ApiListingResource;
+
+@Provider(Type.Feature)
+public class Swagger2Feature extends AbstractSwaggerFeature {
+
+ protected boolean dynamicBasePath;
+
+ protected boolean replaceTags;
+
+ protected DocumentationProvider javadocProvider;
+
+ private String host;
+
+ private String[] schemes;
+
+ private boolean prettyPrint;
+
+ private boolean scanAllResources;
+
+ private String ignoreRoutes;
+
+ @Override
+ protected void addSwaggerResource(Server server) {
+ ApiListingResource apiListingResource = new ApiListingResource();
+ JAXRSServiceFactoryBean sfb =
+ (JAXRSServiceFactoryBean) server.getEndpoint().get(JAXRSServiceFactoryBean.class.getName());
+ sfb.setResourceClassesFromBeans(Collections.<Object>singletonList(apiListingResource));
+ List<ClassResourceInfo> cris = sfb.getClassResourceInfo();
+
+ List<Object> providers = new ArrayList<>();
+ if (runAsFilter) {
+ providers.add(new SwaggerContainerRequestFilter());
+ } else {
+ for (ClassResourceInfo cri : cris) {
+ if (ApiListingResource.class == cri.getResourceClass()) {
+ InjectionUtils.injectContextProxies(cri, apiListingResource);
+ }
+ }
+ }
+ providers.add(new Swagger2Serializers(dynamicBasePath, replaceTags, javadocProvider, cris));
+ providers.add(new ReaderConfigFilter());
+ ((ServerProviderFactory) server.getEndpoint().get(
+ ServerProviderFactory.class.getName())).setUserProviders(providers);
+
+ BeanConfig beanConfig = new BeanConfig();
+ beanConfig.setResourcePackage(getResourcePackage());
+ beanConfig.setVersion(getVersion());
+ beanConfig.setBasePath(getBasePath());
+ beanConfig.setHost(getHost());
+ beanConfig.setSchemes(getSchemes());
+ beanConfig.setTitle(getTitle());
+ beanConfig.setDescription(getDescription());
+ beanConfig.setContact(getContact());
+ beanConfig.setLicense(getLicense());
+ beanConfig.setLicenseUrl(getLicenseUrl());
+ beanConfig.setTermsOfServiceUrl(getTermsOfServiceUrl());
+ beanConfig.setScan(isScan());
+ beanConfig.setPrettyPrint(isPrettyPrint());
+ beanConfig.setFilterClass(getFilterClass());
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public String[] getSchemes() {
+ return schemes;
+ }
+
+ public void setSchemes(String[] schemes) {
+ this.schemes = schemes;
+ }
+
+ public boolean isPrettyPrint() {
+ return prettyPrint;
+ }
+
+ public void setPrettyPrint(boolean prettyPrint) {
+ this.prettyPrint = prettyPrint;
+ }
+
+ public boolean isScanAllResources() {
+ return scanAllResources;
+ }
+
+ public void setScanAllResources(boolean scanAllResources) {
+ this.scanAllResources = scanAllResources;
+ }
+
+ public String getIgnoreRoutes() {
+ return ignoreRoutes;
+ }
+
+ public void setIgnoreRoutes(String ignoreRoutes) {
+ this.ignoreRoutes = ignoreRoutes;
+ }
+
+ public void setDynamicBasePath(final boolean dynamicBasePath) {
+ this.dynamicBasePath = dynamicBasePath;
+ }
+
+ public void setReplaceTags(final boolean replaceTags) {
+ this.replaceTags = replaceTags;
+ }
+
+ public void setJavaDocPath(final String javaDocPath) throws Exception {
+ this.javadocProvider = new JavaDocProvider(javaDocPath);
+ }
+
+ public void setJavaDocPaths(final String... javaDocPaths) throws Exception {
+ this.javadocProvider = new JavaDocProvider(javaDocPaths);
+ }
+
+ public void setJavaDocURLs(final URL[] javaDocURLs) {
+ this.javadocProvider = new JavaDocProvider(javaDocURLs);
+ }
+
+ @Override
+ protected void setBasePathByAddress(String address) {
+ if (!address.startsWith("/")) {
+ // get the path part
+ URI u = URI.create(address);
+ setBasePath(u.getPath());
+ setHost(u.getPort() < 0 ? u.getHost() : u.getHost() + ":" + u.getPort());
+ } else {
+ setBasePath(address);
+ }
+ }
+
+ @PreMatching
+ protected static class SwaggerContainerRequestFilter extends ApiListingResource implements ContainerRequestFilter {
+
+ protected static final MediaType APPLICATION_YAML_TYPE = JAXRSUtils.toMediaType("application/yaml");
+
+ protected static final String APIDOCS_LISTING_PATH = "swagger";
+
+ protected static final String APIDOCS_LISTING_PATH_JSON = APIDOCS_LISTING_PATH + ".json";
+
+ protected static final String APIDOCS_LISTING_PATH_YAML = APIDOCS_LISTING_PATH + ".yaml";
+
+ @Context
+ protected MessageContext mc;
+
+ @Override
+ public void filter(ContainerRequestContext requestContext) throws IOException {
+ UriInfo ui = mc.getUriInfo();
+ List<MediaType> mediaTypes = mc.getHttpHeaders().getAcceptableMediaTypes();
+
+ Response response = null;
+ if ((ui.getPath().endsWith(APIDOCS_LISTING_PATH)
+ && !JAXRSUtils.intersectMimeTypes(mediaTypes, MediaType.APPLICATION_JSON_TYPE).isEmpty())
+ || ui.getPath().endsWith(APIDOCS_LISTING_PATH_JSON)) {
+
+ response = getListingJsonResponse(
+ null, mc.getServletContext(), mc.getServletConfig(), mc.getHttpHeaders(), ui);
+ } else if ((ui.getPath().endsWith(APIDOCS_LISTING_PATH)
+ && !JAXRSUtils.intersectMimeTypes(mediaTypes, APPLICATION_YAML_TYPE).isEmpty())
+ || ui.getPath().endsWith(APIDOCS_LISTING_PATH_YAML)) {
+
+ response = getListingYamlResponse(
+ null, mc.getServletContext(), mc.getServletConfig(), mc.getHttpHeaders(), ui);
+ }
+
+ if (response != null) {
+ requestContext.abortWith(response);
+ }
+ }
+ }
+
+ protected class ReaderConfigFilter implements ContainerRequestFilter {
+
+ @Context
+ protected MessageContext mc;
+
+ @Override
+ public void filter(ContainerRequestContext requestContext) throws IOException {
+ ServletContext servletContext = mc.getServletContext();
+ if (servletContext != null && servletContext.getAttribute(ReaderConfig.class.getName()) == null) {
+ if (mc.getServletConfig() != null
+ && Boolean.valueOf(mc.getServletConfig().getInitParameter("scan.all.resources"))) {
+ addReaderConfig(mc.getServletConfig().getInitParameter("ignore.routes"));
+ } else if (isScanAllResources()) {
+ addReaderConfig(getIgnoreRoutes());
+ }
+ }
+ }
+
+ protected void addReaderConfig(String ignoreRoutesParam) {
+ DefaultReaderConfig rc = new DefaultReaderConfig();
+ rc.setScanAllResources(true);
+ if (ignoreRoutesParam != null) {
+ Set<String> routes = new LinkedHashSet<>();
+ for (String route : StringUtils.split(ignoreRoutesParam, ",")) {
+ routes.add(route.trim());
+ }
+ rc.setIgnoredRoutes(routes);
+ }
+ mc.getServletContext().setAttribute(ReaderConfig.class.getName(), rc);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Serializers.java
----------------------------------------------------------------------
diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Serializers.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Serializers.java
new file mode 100644
index 0000000..e6f7be2
--- /dev/null
+++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Serializers.java
@@ -0,0 +1,164 @@
+/**
+ * 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.swagger;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.model.doc.DocumentationProvider;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+
+import io.swagger.jaxrs.listing.SwaggerSerializers;
+import io.swagger.models.HttpMethod;
+import io.swagger.models.Operation;
+import io.swagger.models.Path;
+import io.swagger.models.Swagger;
+import io.swagger.models.Tag;
+
+public class Swagger2Serializers extends SwaggerSerializers {
+
+ protected final boolean dynamicBasePath;
+
+ protected final boolean replaceTags;
+
+ protected final DocumentationProvider javadocProvider;
+
+ protected final List<ClassResourceInfo> cris;
+
+ public Swagger2Serializers(
+ final boolean dynamicBasePath,
+ final boolean replaceTags,
+ final DocumentationProvider javadocProvider,
+ final List<ClassResourceInfo> cris) {
+
+ super();
+
+ this.dynamicBasePath = dynamicBasePath;
+ this.replaceTags = replaceTags;
+ this.javadocProvider = javadocProvider;
+ this.cris = cris;
+ }
+
+ @Override
+ public void writeTo(
+ final Swagger data,
+ final Class<?> type,
+ final Type genericType,
+ final Annotation[] annotations,
+ final MediaType mediaType,
+ final MultivaluedMap<String, Object> headers,
+ final OutputStream out) throws IOException {
+
+ if (dynamicBasePath) {
+ MessageContext ctx = JAXRSUtils.createContextValue(
+ JAXRSUtils.getCurrentMessage(), null, MessageContext.class);
+ data.setBasePath(StringUtils.substringBeforeLast(ctx.getHttpServletRequest().getRequestURI(), "/"));
+ }
+
+ if (replaceTags || javadocProvider != null) {
+ Map<String, ClassResourceInfo> operations = new HashMap<>();
+ Map<Pair<String, String>, OperationResourceInfo> methods = new HashMap<>();
+ for (ClassResourceInfo cri : cris) {
+ for (OperationResourceInfo ori : cri.getMethodDispatcher().getOperationResourceInfos()) {
+ String normalizedPath = getNormalizedPath(
+ cri.getURITemplate().getValue(), ori.getURITemplate().getValue());
+
+ operations.put(normalizedPath, cri);
+ methods.put(ImmutablePair.of(ori.getHttpMethod(), normalizedPath), ori);
+ }
+ }
+
+ if (replaceTags && data.getTags() != null) {
+ data.getTags().clear();
+ }
+ for (final Map.Entry<String, Path> entry : data.getPaths().entrySet()) {
+ Tag tag = null;
+ if (replaceTags && operations.containsKey(entry.getKey())) {
+ ClassResourceInfo cri = operations.get(entry.getKey());
+
+ tag = new Tag();
+ tag.setName(cri.getURITemplate().getValue());
+ if (javadocProvider != null) {
+ tag.setDescription(javadocProvider.getClassDoc(cri));
+ }
+
+ data.addTag(tag);
+ }
+
+ for (Map.Entry<HttpMethod, Operation> subentry : entry.getValue().getOperationMap().entrySet()) {
+ if (replaceTags && tag != null) {
+ subentry.getValue().setTags(Collections.singletonList(tag.getName()));
+ }
+
+ Pair<String, String> key = ImmutablePair.of(subentry.getKey().name(), entry.getKey());
+ if (methods.containsKey(key) && javadocProvider != null) {
+ OperationResourceInfo ori = methods.get(key);
+
+ subentry.getValue().setSummary(javadocProvider.getMethodDoc(ori));
+ for (int i = 0; i < subentry.getValue().getParameters().size(); i++) {
+ subentry.getValue().getParameters().get(i).
+ setDescription(javadocProvider.getMethodParameterDoc(ori, i));
+ }
+
+ if (subentry.getValue().getResponses() != null
+ && !subentry.getValue().getResponses().isEmpty()) {
+
+ subentry.getValue().getResponses().entrySet().iterator().next().getValue().
+ setDescription(javadocProvider.getMethodResponseDoc(ori));
+ }
+ }
+ }
+ }
+ }
+
+ super.writeTo(data, type, genericType, annotations, mediaType, headers, out);
+ }
+
+ protected String getNormalizedPath(String classResourcePath, String operationResourcePath) {
+ StringBuilder normalizedPath = new StringBuilder();
+
+ String[] segments = StringUtils.split(classResourcePath + operationResourcePath, "/");
+ for (String segment : segments) {
+ if (!StringUtils.isEmpty(segment)) {
+ normalizedPath.append("/").append(segment);
+ }
+ }
+ // Adapt to Swagger's path expression
+ if (normalizedPath.toString().endsWith(":.*}")) {
+ normalizedPath.setLength(normalizedPath.length() - 4);
+ normalizedPath.append('}');
+ }
+ return StringUtils.EMPTY.equals(normalizedPath.toString()) ? "/" : normalizedPath.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/SwaggerFeature.java
----------------------------------------------------------------------
diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/SwaggerFeature.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/SwaggerFeature.java
new file mode 100644
index 0000000..0a4162b
--- /dev/null
+++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/SwaggerFeature.java
@@ -0,0 +1,115 @@
+/**
+ * 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.swagger;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.PreMatching;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import com.wordnik.swagger.jaxrs.config.BeanConfig;
+import com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider;
+import com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON;
+import com.wordnik.swagger.jaxrs.listing.ResourceListingProvider;
+
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean;
+import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.jaxrs.provider.ServerProviderFactory;
+
+public class SwaggerFeature extends AbstractSwaggerFeature {
+
+ @Override
+ protected void addSwaggerResource(Server server) {
+ ApiListingResourceJSON apiListingResource = new ApiListingResourceJSON();
+ if (!runAsFilter) {
+ List<Object> serviceBeans = new ArrayList<Object>();
+ serviceBeans.add(apiListingResource);
+ ((JAXRSServiceFactoryBean)server.getEndpoint().get(JAXRSServiceFactoryBean.class.getName())).
+ setResourceClassesFromBeans(serviceBeans);
+ }
+ List<Object> providers = new ArrayList<Object>();
+ if (runAsFilter) {
+ providers.add(new SwaggerContainerRequestFilter(apiListingResource));
+ }
+ providers.add(new ResourceListingProvider());
+ providers.add(new ApiDeclarationProvider());
+ ((ServerProviderFactory)server.getEndpoint().get(
+ ServerProviderFactory.class.getName())).setUserProviders(providers);
+
+ BeanConfig beanConfig = new BeanConfig();
+ beanConfig.setResourcePackage(getResourcePackage());
+ beanConfig.setVersion(getVersion());
+ beanConfig.setBasePath(getBasePath());
+ beanConfig.setTitle(getTitle());
+ beanConfig.setDescription(getDescription());
+ beanConfig.setContact(getContact());
+ beanConfig.setLicense(getLicense());
+ beanConfig.setLicenseUrl(getLicenseUrl());
+ beanConfig.setTermsOfServiceUrl(getTermsOfServiceUrl());
+ beanConfig.setScan(isScan());
+ beanConfig.setFilterClass(getFilterClass());
+ }
+
+ @Override
+ protected void setBasePathByAddress(String address) {
+ setBasePath(address);
+ }
+
+ @PreMatching
+ private static class SwaggerContainerRequestFilter implements ContainerRequestFilter {
+ private static final String APIDOCS_LISTING_PATH = "api-docs";
+ private static final Pattern APIDOCS_RESOURCE_PATH = Pattern.compile(APIDOCS_LISTING_PATH + "(/.+)");
+
+ private ApiListingResourceJSON apiListingResource;
+ @Context
+ private MessageContext mc;
+ SwaggerContainerRequestFilter(ApiListingResourceJSON apiListingResource) {
+ this.apiListingResource = apiListingResource;
+ }
+
+ @Override
+ public void filter(ContainerRequestContext requestContext) throws IOException {
+ UriInfo ui = mc.getUriInfo();
+ if (ui.getPath().endsWith(APIDOCS_LISTING_PATH)) {
+ Response r =
+ apiListingResource.resourceListing(null, mc.getServletConfig(), mc.getHttpHeaders(), ui);
+ requestContext.abortWith(r);
+ } else {
+ final Matcher matcher = APIDOCS_RESOURCE_PATH.matcher(ui.getPath());
+
+ if (matcher.find()) {
+ Response r =
+ apiListingResource.apiDeclaration(matcher.group(1),
+ null, mc.getServletConfig(), mc.getHttpHeaders(), ui);
+ requestContext.abortWith(r);
+ }
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/SwaggerUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/SwaggerUtils.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/SwaggerUtils.java
new file mode 100644
index 0000000..2438458
--- /dev/null
+++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/SwaggerUtils.java
@@ -0,0 +1,233 @@
+/**
+ * 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.swagger;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
+import org.apache.cxf.jaxrs.model.Parameter;
+import org.apache.cxf.jaxrs.model.ParameterType;
+import org.apache.cxf.jaxrs.model.UserOperation;
+import org.apache.cxf.jaxrs.model.UserResource;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+
+public final class SwaggerUtils {
+ private static final Logger LOG = LogUtils.getL7dLogger(ResourceUtils.class);
+ private static final Map<String, String> SWAGGER_TYPE_MAP;
+ static {
+ SWAGGER_TYPE_MAP = new HashMap<String, String>();
+ SWAGGER_TYPE_MAP.put("string", "String");
+ SWAGGER_TYPE_MAP.put("integer", "long");
+ SWAGGER_TYPE_MAP.put("float", "float");
+ SWAGGER_TYPE_MAP.put("double", "double");
+ SWAGGER_TYPE_MAP.put("int", "int");
+ SWAGGER_TYPE_MAP.put("long", "long");
+ SWAGGER_TYPE_MAP.put("byte", "byte");
+ SWAGGER_TYPE_MAP.put("boolean", "boolean");
+ SWAGGER_TYPE_MAP.put("date", "java.util.Date");
+ SWAGGER_TYPE_MAP.put("dateTime", "java.util.Date");
+ SWAGGER_TYPE_MAP.put("File", "java.io.InputStream");
+ SWAGGER_TYPE_MAP.put("file", "java.io.InputStream");
+ }
+ private SwaggerUtils() {
+
+ }
+ public static UserResource getUserResource(String loc) {
+ return getUserResource(loc, BusFactory.getThreadDefaultBus());
+ }
+ public static UserResource getUserResource(String loc, Bus bus) {
+ try {
+ InputStream is = ResourceUtils.getResourceStream(loc, bus);
+ if (is == null) {
+ return null;
+ }
+ return getUserResourceFromJson(IOUtils.readStringFromStream(is));
+ } catch (Exception ex) {
+ LOG.warning("Problem with processing a user model at " + loc);
+ }
+ return null;
+ }
+ public static List<UserResource> getUserResourcesFromResourceObjects(List<String> jsonObjects) {
+ List<UserResource> resources = new ArrayList<UserResource>();
+ for (String json : jsonObjects) {
+ resources.add(getUserResourceFromJson(json));
+ }
+ return resources;
+ }
+ public static UserResource getUserResourceFromJson(String json) {
+ JsonMapObjectReaderWriter reader = new JsonMapObjectReaderWriter();
+ Map<String, Object> map = reader.fromJson(json);
+
+ if (map.containsKey("swaggerVersion")) {
+ return getUserResourceFromSwagger12(map);
+ } else {
+ return getUserResourceFromSwagger20(map);
+ }
+
+ }
+ private static UserResource getUserResourceFromSwagger20(Map<String, Object> map) {
+ UserResource ur = new UserResource();
+ String relativePath = (String)map.get("basePath");
+ ur.setPath(relativePath == null ? "/" : relativePath);
+
+ List<String> resourceProduces = CastUtils.cast((List<?>)map.get("produces"));
+ ur.setProduces(listToString(resourceProduces));
+
+ List<String> resourceConsumes = CastUtils.cast((List<?>)map.get("consumes"));
+ ur.setConsumes(listToString(resourceConsumes));
+
+ List<UserOperation> userOps = new LinkedList<UserOperation>();
+ Map<String, Map<String, Object>> paths = CastUtils.cast((Map<?, ?>)map.get("paths"));
+ for (Map.Entry<String, Map<String, Object>> pathEntry : paths.entrySet()) {
+
+ String operPath = pathEntry.getKey();
+
+ Map<String, Object> operations = pathEntry.getValue();
+ for (Map.Entry<String, Object> operEntry : operations.entrySet()) {
+ UserOperation userOp = new UserOperation();
+ userOp.setVerb(operEntry.getKey().toUpperCase());
+ userOp.setPath(operPath);
+
+ Map<String, Object> oper = CastUtils.cast((Map<?, ?>)operEntry.getValue());
+
+ userOp.setName((String)oper.get("operationId"));
+ List<String> opProduces = CastUtils.cast((List<?>)oper.get("produces"));
+ userOp.setProduces(listToString(opProduces));
+
+ List<String> opConsumes = CastUtils.cast((List<?>)oper.get("consumes"));
+ userOp.setConsumes(listToString(opConsumes));
+
+ List<Parameter> userOpParams = new LinkedList<Parameter>();
+ List<Map<String, Object>> params = CastUtils.cast((List<?>)oper.get("parameters"));
+ for (Map<String, Object> param : params) {
+ String name = (String)param.get("name");
+ //"query", "header", "path", "formData" or "body"
+ String paramType = (String)param.get("in");
+ ParameterType pType = "body".equals(paramType) ? ParameterType.REQUEST_BODY
+ : "formData".equals(paramType)
+ ? ParameterType.FORM : ParameterType.valueOf(paramType.toUpperCase());
+ Parameter userParam = new Parameter(pType, name);
+
+ setJavaType(userParam, (String)param.get("type"));
+
+ userOpParams.add(userParam);
+ }
+ if (!userOpParams.isEmpty()) {
+ userOp.setParameters(userOpParams);
+ }
+ userOps.add(userOp);
+ }
+ }
+ ur.setOperations(userOps);
+ return ur;
+ }
+ private static UserResource getUserResourceFromSwagger12(Map<String, Object> map) {
+ UserResource ur = new UserResource();
+ String relativePath = (String)map.get("resourcePath");
+ ur.setPath(relativePath == null ? "/" : relativePath);
+
+ List<String> resourceProduces = CastUtils.cast((List<?>)map.get("produces"));
+ ur.setProduces(listToString(resourceProduces));
+
+ List<String> resourceConsumes = CastUtils.cast((List<?>)map.get("consumes"));
+ ur.setConsumes(listToString(resourceConsumes));
+
+ List<UserOperation> userOps = new LinkedList<UserOperation>();
+ List<Map<String, Object>> apis = CastUtils.cast((List<?>)map.get("apis"));
+ for (Map<String, Object> api : apis) {
+ String operPath = (String)api.get("path");
+ if (relativePath != null && operPath.startsWith(relativePath)
+ && operPath.length() > relativePath.length()) {
+ // relative resource and operation paths overlap in Swagger 1.2
+ operPath = operPath.substring(relativePath.length());
+ }
+
+ List<Map<String, Object>> operations = CastUtils.cast((List<?>)api.get("operations"));
+ for (Map<String, Object> oper : operations) {
+ UserOperation userOp = new UserOperation();
+ userOp.setPath(operPath);
+ userOp.setName((String)oper.get("nickname"));
+ userOp.setVerb((String)oper.get("method"));
+
+ List<String> opProduces = CastUtils.cast((List<?>)oper.get("produces"));
+ userOp.setProduces(listToString(opProduces));
+
+ List<String> opConsumes = CastUtils.cast((List<?>)oper.get("consumes"));
+ userOp.setConsumes(listToString(opConsumes));
+
+ List<Parameter> userOpParams = new LinkedList<Parameter>();
+ List<Map<String, Object>> params = CastUtils.cast((List<?>)oper.get("parameters"));
+ for (Map<String, Object> param : params) {
+ String name = (String)param.get("name");
+ //"path", "query", "body", "header", "form"
+ String paramType = (String)param.get("paramType");
+ ParameterType pType = "body".equals(paramType)
+ ? ParameterType.REQUEST_BODY : ParameterType.valueOf(paramType.toUpperCase());
+ Parameter userParam = new Parameter(pType, name);
+ setJavaType(userParam, (String)param.get("type"));
+
+ userOpParams.add(userParam);
+ }
+ if (!userOpParams.isEmpty()) {
+ userOp.setParameters(userOpParams);
+ }
+ userOps.add(userOp);
+ }
+ }
+ ur.setOperations(userOps);
+ return ur;
+ }
+ private static void setJavaType(Parameter userParam, String typeName) {
+ String javaTypeName = SWAGGER_TYPE_MAP.get(typeName);
+ if (javaTypeName != null) {
+ try {
+ userParam.setJavaType(ClassLoaderUtils.loadClass(javaTypeName, SwaggerUtils.class));
+ } catch (Throwable t) {
+ // ignore - can be a reference to a JSON model class, etc
+ }
+ }
+
+ }
+ private static String listToString(List<String> list) {
+ if (list != null) {
+ StringBuilder sb = new StringBuilder();
+ for (String s : list) {
+ if (sb.length() > 0) {
+ sb.append(',');
+ }
+ sb.append(s);
+ }
+ return sb.toString();
+ } else {
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/rs/description-swagger/src/main/resources/META-INF/services/io.swagger.jaxrs.ext.SwaggerExtension
----------------------------------------------------------------------
diff --git a/rt/rs/description-swagger/src/main/resources/META-INF/services/io.swagger.jaxrs.ext.SwaggerExtension b/rt/rs/description-swagger/src/main/resources/META-INF/services/io.swagger.jaxrs.ext.SwaggerExtension
new file mode 100644
index 0000000..9803485
--- /dev/null
+++ b/rt/rs/description-swagger/src/main/resources/META-INF/services/io.swagger.jaxrs.ext.SwaggerExtension
@@ -0,0 +1 @@
+org.apache.cxf.jaxrs.swagger.JaxRs2Extension
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/Swagger2FeatureTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/Swagger2FeatureTest.java b/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/Swagger2FeatureTest.java
new file mode 100644
index 0000000..c87b041
--- /dev/null
+++ b/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/Swagger2FeatureTest.java
@@ -0,0 +1,53 @@
+/**
+ * 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.swagger;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class Swagger2FeatureTest extends Assert {
+ @Test
+ public void testSetBasePathByAddress() {
+ Swagger2Feature f = new Swagger2Feature();
+
+ f.setBasePathByAddress("http://localhost:8080/foo");
+ assertEquals("/foo", f.getBasePath());
+ assertEquals("localhost:8080", f.getHost());
+ unsetBasePath(f);
+
+ f.setBasePathByAddress("http://localhost/foo");
+ assertEquals("/foo", f.getBasePath());
+ assertEquals("localhost", f.getHost());
+ unsetBasePath(f);
+
+ f.setBasePathByAddress("/foo");
+ assertEquals("/foo", f.getBasePath());
+ assertNull(f.getHost());
+ unsetBasePath(f);
+ }
+
+ private static void unsetBasePath(Swagger2Feature f) {
+ f.setBasePath(null);
+ f.setHost(null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/636252c2/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/SwaggerFeatureTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/SwaggerFeatureTest.java b/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/SwaggerFeatureTest.java
new file mode 100644
index 0000000..a1922d5
--- /dev/null
+++ b/rt/rs/description-swagger/src/test/java/org/apache/cxf/jaxrs/swagger/SwaggerFeatureTest.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 org.apache.cxf.jaxrs.swagger;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class SwaggerFeatureTest extends Assert {
+ @Test
+ public void testSetBasePathByAddress() {
+ SwaggerFeature f = new SwaggerFeature();
+
+ f.setBasePathByAddress("http://localhost:8080/foo");
+ assertEquals("http://localhost:8080/foo", f.getBasePath());
+ unsetBasePath(f);
+
+ f.setBasePathByAddress("/foo");
+ assertEquals("/foo", f.getBasePath());
+ unsetBasePath(f);
+ }
+
+ private static void unsetBasePath(SwaggerFeature f) {
+ f.setBasePath(null);
+ }
+}