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);
+    }
+}