You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2013/12/27 19:10:38 UTC

svn commit: r1553709 - in /cxf/trunk/rt/rs/description/src: main/java/org/apache/cxf/jaxrs/model/wadl/ test/java/org/apache/cxf/jaxrs/model/wadl/ test/java/org/apache/cxf/jaxrs/model/wadl/petstore/ test/resources/javadocs/

Author: sergeyb
Date: Fri Dec 27 18:10:38 2013
New Revision: 1553709

URL: http://svn.apache.org/r1553709
Log:
[CXF-5353] Initial attempt at scraping Java docs from HTML

Added:
    cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/DocumentationProvider.java   (with props)
    cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProvider.java   (with props)
    cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProviderTest.java   (with props)
    cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/
    cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java   (with props)
    cxf/trunk/rt/rs/description/src/test/resources/javadocs/
    cxf/trunk/rt/rs/description/src/test/resources/javadocs/pet-store-javadoc16.jar   (with props)
    cxf/trunk/rt/rs/description/src/test/resources/javadocs/pet-store-javadoc17.jar   (with props)
Modified:
    cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java

Added: cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/DocumentationProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/DocumentationProvider.java?rev=1553709&view=auto
==============================================================================
--- cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/DocumentationProvider.java (added)
+++ cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/DocumentationProvider.java Fri Dec 27 18:10:38 2013
@@ -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.wadl;
+
+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);
+}

Propchange: cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/DocumentationProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/DocumentationProvider.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProvider.java?rev=1553709&view=auto
==============================================================================
--- cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProvider.java (added)
+++ cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProvider.java Fri Dec 27 18:10:38 2013
@@ -0,0 +1,301 @@
+/**
+ * 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;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+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;
+
+    private ClassLoader javaDocLoader;
+    private ConcurrentHashMap<String, ClassDocs> docs = new ConcurrentHashMap<String, ClassDocs>();
+    
+    public JavaDocProvider(URL javaDocUrl) {
+        if (javaDocUrl == null) {
+            throw new IllegalArgumentException("URL is null");
+        }
+        javaDocLoader = new URLClassLoader(new URL[]{javaDocUrl});
+    }
+    
+    public JavaDocProvider(String path) throws Exception {
+        this(BusFactory.getDefaultBus(), path);
+    }
+    
+    public JavaDocProvider(Bus bus, String path) throws Exception {
+        this(ResourceUtils.getResourceURL(path, bus));
+    }
+    
+    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;
+        }
+    }
+    
+    public String getClassDoc(ClassResourceInfo cri) {
+        try {
+            ClassDocs doc = getClassDocInternal(cri);
+            if (doc == null) {
+                return null;
+            }
+            return doc.getClassInfo();
+        } catch (Exception ex) {
+            // ignore    
+        }
+        return null;
+    }
+    
+    public String getMethodDoc(OperationResourceInfo ori) {
+        try {
+            MethodDocs doc = getOperationDocInternal(ori);
+            if (doc == null) {
+                return null;
+            }
+            return doc.getMethodInfo();
+        } catch (Exception ex) {
+            // ignore
+        }
+        return null;
+    }
+    
+    public String getMethodResponseDoc(OperationResourceInfo ori) {
+        try {
+            MethodDocs doc = getOperationDocInternal(ori);
+            if (doc == null) {
+                return null;
+            }
+            return doc.getResponseInfo();
+        } catch (Exception ex) {
+            // ignore    
+        }
+        return null;
+    }
+    
+    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 ClassDocs getClassDocInternal(ClassResourceInfo cri) throws Exception {
+        String resource = cri.getServiceClass().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 classMarker = "Class " + cri.getServiceClass().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 {
+        ClassDocs classDoc = getClassDocInternal(ori.getClassResourceInfo());
+        if (classDoc == null) {
+            return null;
+        }
+        String methodName = ori.getMethodToInvoke().getName();
+        MethodDocs mDocs = classDoc.getMethodDocs(methodName);
+        if (mDocs == null) {
+            String operLink = getOperLink();
+            String operMarker = operLink + methodName + "(";
+            int operMarkerIndex = classDoc.getClassDoc().indexOf(operMarker);
+            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<String>();
+            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(methodName, 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 (JAVA_VERSION == JAVA_VERSION_16) {
+            return "<P>";
+        } else {
+            return "<div class=\"block\">";
+        }
+    }
+    protected String getOperInfoTag() {
+        if (JAVA_VERSION == JAVA_VERSION_16) {
+            return "<DD>";
+        } else {
+            return "<div class=\"block\">";
+        }
+    }
+    protected String getOperLink() {
+        String operLink = "<A NAME=\"";
+        return JAVA_VERSION == JAVA_VERSION_16 ? operLink : operLink.toLowerCase();
+    }
+    
+    protected String getResponseMarker() {
+        String tag = "<DD>";
+        return JAVA_VERSION == JAVA_VERSION_16 ? tag : tag.toLowerCase();
+    }
+    
+    protected String getCodeTag() {
+        String tag = "</CODE>";
+        return JAVA_VERSION == JAVA_VERSION_16 ? tag : tag.toLowerCase();
+    }
+    private static class ClassDocs {
+        private String classDoc;
+        private String classInfo;
+        private ConcurrentHashMap<String, MethodDocs> mdocs = new ConcurrentHashMap<String, MethodDocs>(); 
+        public ClassDocs(String classDoc, String classInfo) {
+            this.classDoc = classDoc;
+            this.classInfo = classInfo;
+        }
+        
+        public String getClassDoc() {
+            return classDoc;
+        }
+        
+        public String getClassInfo() {
+            return classInfo;
+        }
+        
+        public MethodDocs getMethodDocs(String name) {
+            return mdocs.get(name);
+        }
+        
+        public void addMethodDocs(String name, MethodDocs doc) {
+            mdocs.putIfAbsent(name, doc);
+        }
+    }
+    
+    private static class MethodDocs {
+        private String methodInfo;
+        private List<String> paramInfo = new LinkedList<String>();
+        private String responseInfo;
+        public 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;
+        }
+    }
+}

Propchange: cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProvider.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java?rev=1553709&r1=1553708&r2=1553709&view=diff
==============================================================================
--- cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java (original)
+++ cxf/trunk/rt/rs/description/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java Fri Dec 27 18:10:38 2013
@@ -154,6 +154,7 @@ public class WadlGenerator implements Co
     private String nsPrefix = DEFAULT_NS_PREFIX;
     private MediaType defaultMediaType = DEFAULT_MEDIA_TYPE;
     private Bus bus;
+    private DocumentationProvider docProvider;
         
     public WadlGenerator() {
     }
@@ -246,6 +247,8 @@ public class WadlGenerator implements Co
             }
             if (description != null) {
                 handleDocs(new Annotation[] {description}, sbResources, DocTarget.RESOURCE, true, isJson);
+            } else {
+                handleClassJavaDocs(cri, sbResources);
             }
             handleResource(sbResources, allTypes, qnameResolver, clsMap, cri, visitedResources, isJson);
             sbResources.append("</resource>");
@@ -470,22 +473,24 @@ public class WadlGenerator implements Co
             }
             sb.append("<resource path=\"").append(getPath(path)).append("\">");
             handleDocs(anns, sb, DocTarget.RESOURCE, false, isJson);
-            handlePathAndMatrixClassParams(sb, classParams, isJson);
+            handlePathAndMatrixClassParams(ori, sb, classParams, isJson);
             handlePathAndMatrixParams(sb, ori, isJson);
         } else if (index == 0) {
-            handlePathAndMatrixClassParams(sb, classParams, isJson);
+            handlePathAndMatrixClassParams(ori, sb, classParams, isJson);
             handlePathAndMatrixParams(sb, ori, isJson);
         }
 
         startMethodTag(sb, ori);
-        handleDocs(anns, sb, DocTarget.METHOD, true, isJson);
+        if (!handleDocs(anns, sb, DocTarget.METHOD, true, isJson)) {
+            handleOperJavaDocs(ori, sb);
+        }
         if (getMethod(ori).getParameterTypes().length != 0 || classParams.size() != 0) {
             sb.append("<request>");
             handleDocs(anns, sb, DocTarget.REQUEST, false, isJson);
 
             boolean isForm = isFormRequest(ori);
 
-            doHandleClassParams(sb, classParams, isJson, ParameterType.QUERY, ParameterType.HEADER);
+            doHandleClassParams(ori, sb, classParams, isJson, ParameterType.QUERY, ParameterType.HEADER);
             for (Parameter p : ori.getParameters()) {
                 if (isForm && p.getType() == ParameterType.REQUEST_BODY) {
                     continue;
@@ -574,13 +579,18 @@ public class WadlGenerator implements Co
         sb.append("</resource>");
     }
 
-    protected void handlePathAndMatrixClassParams(StringBuilder sb, Map<Parameter, Object> params,
+    protected void handlePathAndMatrixClassParams(OperationResourceInfo ori,
+                                                  StringBuilder sb, 
+                                                  Map<Parameter, Object> params,
                                                   boolean isJson) {
-        doHandleClassParams(sb, params, isJson, ParameterType.PATH);
-        doHandleClassParams(sb, params, isJson, ParameterType.MATRIX);
+        doHandleClassParams(ori, sb, params, isJson, ParameterType.PATH);
+        doHandleClassParams(ori, sb, params, isJson, ParameterType.MATRIX);
     }
 
-    protected void doHandleClassParams(StringBuilder sb, Map<Parameter, Object> params, boolean isJson,
+    protected void doHandleClassParams(OperationResourceInfo ori,
+                                       StringBuilder sb, 
+                                       Map<Parameter, Object> params, 
+                                       boolean isJson,
                                        ParameterType... pType) {
         Set<ParameterType> pTypes = new LinkedHashSet<ParameterType>(Arrays.asList(pType));
         for (Map.Entry<Parameter, Object> entry : params.entrySet()) {
@@ -593,7 +603,7 @@ public class WadlGenerator implements Co
                     ? ((Method)obj).getGenericParameterTypes()[0] : ((Field)obj).getGenericType();
                 Annotation[] ann = obj instanceof Method
                     ? ((Method)obj).getParameterAnnotations()[0] : ((Field)obj).getAnnotations();
-                doWriteParam(sb, pm, cls, type, pm.getName(), ann, isJson);
+                doWriteParam(ori, sb, pm, cls, type, pm.getName(), ann, isJson);
             }
         }
     }
@@ -647,17 +657,28 @@ public class WadlGenerator implements Co
         Method method = getMethod(ori);
         Class<?> type = method.getParameterTypes()[pm.getIndex()];
         if (!"".equals(pm.getName())) {
-            doWriteParam(sb, pm, type, method.getGenericParameterTypes()[pm.getIndex()], pm.getName(),
-                         method.getParameterAnnotations()[pm.getIndex()], isJson);
+            doWriteParam(ori,
+                         sb,
+                         pm, 
+                         type, 
+                         method.getGenericParameterTypes()[pm.getIndex()], 
+                         pm.getName(),
+                         method.getParameterAnnotations()[pm.getIndex()], 
+                         isJson);
         } else {
             List<Class<?>> parentBeanClasses = new LinkedList<Class<?>>();
             parentBeanClasses.add(type);
-            doWriteBeanParam(sb, type, pm, null, parentBeanClasses, isJson);
+            doWriteBeanParam(ori, sb, type, pm, null, parentBeanClasses, isJson);
         }
     }
 
-    private void doWriteBeanParam(StringBuilder sb, Class<?> type, Parameter pm, String parentName,
-                                  List<Class<?>> parentBeanClasses, boolean isJson) {
+    private void doWriteBeanParam(OperationResourceInfo ori,
+                                  StringBuilder sb, 
+                                  Class<?> type, 
+                                  Parameter pm, 
+                                  String parentName,
+                                  List<Class<?>> parentBeanClasses, 
+                                  boolean isJson) {
         Map<Parameter, Class<?>> pms = InjectionUtils.getParametersFromBeanClass(type, pm.getType(), true);
         for (Map.Entry<Parameter, Class<?>> entry : pms.entrySet()) {
             String name = entry.getKey().getName();
@@ -667,16 +688,23 @@ public class WadlGenerator implements Co
             Class<?> paramCls = entry.getValue();
             boolean isPrimitive = InjectionUtils.isPrimitive(paramCls) || paramCls.isEnum();
             if (isPrimitive || InjectionUtils.isSupportedCollectionOrArray(paramCls)) {
-                doWriteParam(sb, entry.getKey(), paramCls, paramCls, name, new Annotation[] {}, isJson);
+                doWriteParam(ori, sb, entry.getKey(), paramCls, paramCls, name, new Annotation[] {}, isJson);
             } else if (!parentBeanClasses.contains(paramCls)) {
                 parentBeanClasses.add(paramCls);
-                doWriteBeanParam(sb, paramCls, entry.getKey(), name, parentBeanClasses, isJson);
+                doWriteBeanParam(ori, sb, paramCls, entry.getKey(), name, parentBeanClasses, isJson);
             }
         }
     }
-
-    protected void doWriteParam(StringBuilder sb, Parameter pm, Class<?> type, Type genericType,
-                                String paramName, Annotation[] anns, boolean isJson) {
+    //CHECKSTYLE:OFF
+    protected void doWriteParam(OperationResourceInfo ori,
+                                StringBuilder sb, 
+                                Parameter pm, 
+                                Class<?> type, 
+                                Type genericType,
+                                String paramName, 
+                                Annotation[] anns, 
+                                boolean isJson) {
+      //CHECKSTYLE:ON    
         ParameterType pType = pm.getType();
         boolean isForm = isFormParameter(pm, type, anns);
         if (paramName == null && isForm) {
@@ -718,7 +746,7 @@ public class WadlGenerator implements Co
             setEnumOptions(sb, type);
             sb.append("</param>");
         } else {
-            addDocsAndCloseElement(sb, anns, "param", DocTarget.PARAM, true, isJson);
+            addDocsAndCloseElement(ori, pm.getIndex(), sb, anns, "param", DocTarget.PARAM, true, isJson);
         }
     }
 
@@ -736,12 +764,26 @@ public class WadlGenerator implements Co
             // ignore
         }
     }
-
-    private void addDocsAndCloseElement(StringBuilder sb, Annotation[] anns, String elementName,
-                                        String category, boolean allowDefault, boolean isJson) {
-        if (isDocAvailable(anns)) {
+    //CHECKSTYLE:OFF
+    private void addDocsAndCloseElement(OperationResourceInfo ori,
+                                        int paramIndex,
+                                        StringBuilder sb, 
+                                        Annotation[] anns, 
+                                        String elementName,
+                                        String category, 
+                                        boolean allowDefault, 
+                                        boolean isJson) {
+    //CHECKSTYLE:ON    
+        boolean docAnnAvailable = isDocAvailable(anns);
+        if (docAnnAvailable || (ori != null && docProvider != null)) {
             sb.append(">");
-            handleDocs(anns, sb, category, allowDefault, isJson);
+            if (docAnnAvailable) {
+                handleDocs(anns, sb, category, allowDefault, isJson);
+            } else if (category == DocTarget.RETURN) {
+                handleOperResponseJavaDocs(ori, sb);
+            } else if (category == DocTarget.PARAM) {
+                handleOperParamJavaDocs(ori, paramIndex, sb);
+            }
             sb.append("</" + elementName + ">");
         } else {
             sb.append("/>");
@@ -781,9 +823,10 @@ public class WadlGenerator implements Co
             boolean allowDefault = true;
             String docCategory;
             Annotation[] anns;
+            int inParamIndex = -1;
             if (inbound) {
-                int index = getRequestBodyParam(ori).getIndex();
-                anns = opMethod.getParameterAnnotations()[index];
+                inParamIndex = getRequestBodyParam(ori).getIndex();
+                anns = opMethod.getParameterAnnotations()[inParamIndex];
                 if (!isDocAvailable(anns)) {
                     anns = opMethod.getAnnotations();
                 }
@@ -797,7 +840,7 @@ public class WadlGenerator implements Co
                 sb.append(">");
                 Parameter p = inbound ? getRequestBodyParam(ori) : new Parameter(ParameterType.REQUEST_BODY,
                                                                                  0, "result");
-                doWriteParam(sb, p, type, type, p.getName() == null ? "request" : p.getName(), anns, isJson);
+                doWriteParam(ori, sb, p, type, type, p.getName() == null ? "request" : p.getName(), anns, isJson);
                 sb.append("</representation>");
             } else {
                 boolean isCollection = InjectionUtils.isSupportedCollectionOrArray(type);
@@ -817,7 +860,8 @@ public class WadlGenerator implements Co
                     generateQName(sb, qnameResolver, clsMap, theActualType, isCollection,
                                   getBodyAnnotations(ori, inbound));
                 }
-                addDocsAndCloseElement(sb, anns, "representation", docCategory, allowDefault, isJson);
+                addDocsAndCloseElement(ori, inParamIndex, sb, anns, "representation", 
+                                       docCategory, allowDefault, isJson);
             }
         }
 
@@ -1379,13 +1423,49 @@ public class WadlGenerator implements Co
         }
     }
 
-    protected void handleDocs(Annotation[] anns, StringBuilder sb, String category, boolean allowDefault,
-                            boolean isJson) {
+    protected void handleClassJavaDocs(ClassResourceInfo cri, StringBuilder sb) {
+        if (docProvider != null) {
+            addProvidedDocs(sb, docProvider.getClassDoc(cri));
+        }
+    }
+    
+    protected void handleOperJavaDocs(OperationResourceInfo ori, StringBuilder sb) {
+        if (docProvider != null) {
+            addProvidedDocs(sb, docProvider.getMethodDoc(ori));
+        }
+    }
+    
+    protected void handleOperResponseJavaDocs(OperationResourceInfo ori, StringBuilder sb) {
+        if (docProvider != null) {
+            addProvidedDocs(sb, docProvider.getMethodResponseDoc(ori));
+        }
+    }
+    
+    protected void handleOperParamJavaDocs(OperationResourceInfo ori,
+                                           int paramIndex,
+                                           StringBuilder sb) {
+        if (docProvider != null) {
+            addProvidedDocs(sb, docProvider.getMethodParameterDoc(ori, paramIndex));
+        }
+    }
+    
+    private void addProvidedDocs(StringBuilder sb, String text) {
+        if (!StringUtils.isEmpty(text)) {
+            sb.append("<doc>");
+            sb.append(xmlEncodeIfNeeded(text));
+            sb.append("</doc>");
+        }
+    }
+    
+    protected boolean handleDocs(Annotation[] anns, 
+                              StringBuilder sb, 
+                              String category, 
+                              boolean allowDefault,
+                              boolean isJson) {
         for (Annotation a : anns) {
             if (a.annotationType() == Descriptions.class) {
                 Descriptions ds = (Descriptions)a;
-                handleDocs(ds.value(), sb, category, allowDefault, isJson);
-                return;
+                return handleDocs(ds.value(), sb, category, allowDefault, isJson);
             }
             if (a.annotationType() == Description.class) {
                 Description d = (Description)a;
@@ -1420,8 +1500,10 @@ public class WadlGenerator implements Co
                     }
                 }
                 sb.append("</doc>");
+                return true;
             }
         }
+        return false;
     }
 
     private String getNamespace() {
@@ -1792,6 +1874,14 @@ public class WadlGenerator implements Co
     public void setCheckAbsolutePathSlash(boolean checkAbsolutePathSlash) {
         this.checkAbsolutePathSlash = checkAbsolutePathSlash;
     }
+    
+    public void setJavaDocPath(String path) throws Exception {
+        docProvider = new JavaDocProvider(bus == null ? BusFactory.getDefaultBus() : bus, path);
+    }
+    
+    public void setDocumentationProvider(DocumentationProvider p) {
+        docProvider = p;
+    }
 
     private static class SchemaConverter extends DelegatingXMLStreamWriter {
         private static final String SCHEMA_LOCATION = "schemaLocation";

Added: cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProviderTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProviderTest.java?rev=1553709&view=auto
==============================================================================
--- cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProviderTest.java (added)
+++ cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProviderTest.java Fri Dec 27 18:10:38 2013
@@ -0,0 +1,81 @@
+/**
+ * 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;
+
+import org.apache.cxf.common.util.StringUtils;
+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 {
+        if (JavaDocProvider.JAVA_VERSION == JavaDocProvider.JAVA_VERSION_16) {
+            doTestJavaDocs("classpath:/javadocs/pet-store-javadoc16.jar");
+        }
+    }
+    
+    @Test
+    public void testJava7Docs() throws Exception {
+        if (JavaDocProvider.JAVA_VERSION != JavaDocProvider.JAVA_VERSION_16) {
+            //doTestJavaDocs("classpath:/javadocs/pet-store-javadoc17.jar");
+        }
+    }
+    
+    private void doTestJavaDocs(String path) throws Exception {
+        JavaDocProvider p = new JavaDocProvider(path);
+        ClassResourceInfo cri = 
+            ResourceUtils.createClassResourceInfo(PetStore.class, PetStore.class, true, true);
+        String classDoc = p.getClassDoc(cri);
+        assertEquals("The Pet Store", classDoc);
+        
+        boolean getStatusTested = false;
+        boolean noDocsTested = false;
+        for (OperationResourceInfo ori : cri.getMethodDispatcher().getOperationResourceInfos()) {
+            if ("getStatus".equals(ori.getMethodToInvoke().getName())) {
+                testGetStatusJavaDocs(p, ori);
+                getStatusTested = true;
+            } else {
+                testOperWithNoJavaDocs(p, ori);
+                noDocsTested = true;
+            }
+        }
+        assertTrue(getStatusTested);
+        assertTrue(noDocsTested);
+        assertTrue(true);
+    }
+
+    private void testOperWithNoJavaDocs(JavaDocProvider p, OperationResourceInfo ori) {
+        assertTrue(StringUtils.isEmpty(p.getMethodDoc(ori)));
+        assertTrue(StringUtils.isEmpty(p.getMethodResponseDoc(ori)));
+    }
+    
+    private void testGetStatusJavaDocs(JavaDocProvider p, OperationResourceInfo ori) {
+        assertEquals("Return Pet Status", p.getMethodDoc(ori));
+        assertEquals("status", p.getMethodResponseDoc(ori));
+        assertEquals("the pet id", p.getMethodParameterDoc(ori, 0));
+        assertEquals("the query", p.getMethodParameterDoc(ori, 1));
+    }
+    
+}

Propchange: cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProviderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/JavaDocProviderTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java?rev=1553709&view=auto
==============================================================================
--- cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java (added)
+++ cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java Fri Dec 27 18:10:38 2013
@@ -0,0 +1,100 @@
+/**
+ * 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.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+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.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * The Pet Store
+ */
+@Path("/")
+public class PetStore {
+
+    public static final String CLOSED = "The Pet Store is closed";
+
+    public PetStore() {
+    }
+
+    @GET
+    @Produces("text/plain")
+    public Response getBaseStatus() throws Exception {
+
+        return Response.ok(CLOSED).build();
+    }
+    
+    /**
+     * Return Pet Status
+     * @param petId the pet id
+     * @param query the query
+     * @return status 
+     * @throws Exception
+     */
+    @GET
+    @Path("/petstore/pets/{petId}/")
+    @Produces("text/xml")
+    public Response getStatus(@PathParam("petId") String petId,
+                              @QueryParam("query") String query) throws Exception {
+
+        return Response.ok(CLOSED).build();
+    }
+    
+    
+    @GET
+    @Path("/petstore/jaxb/status/")
+    @Produces("text/xml")
+    public PetStoreStatus getJaxbStatus() {
+
+        return new PetStoreStatus();
+    }
+    
+    
+    @GET
+    @POST
+    @Path("/petstore/pets/")
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    @Produces("text/xml")
+    public Response updateStatus(MultivaluedMap<String, String> params) throws Exception {
+        return Response.ok(params.getFirst("status")).build();
+    }
+    
+    @XmlType(name = "status", namespace = "http://pets")
+    public static class PetStoreStatus {
+        private String status = PetStore.CLOSED;
+
+        public String getStatus() {
+            return status;
+        }
+
+        public void setStatus(String status) {
+            this.status = status;
+        }
+        
+    }
+}

Propchange: cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/rs/description/src/test/java/org/apache/cxf/jaxrs/model/wadl/petstore/PetStore.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/trunk/rt/rs/description/src/test/resources/javadocs/pet-store-javadoc16.jar
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/description/src/test/resources/javadocs/pet-store-javadoc16.jar?rev=1553709&view=auto
==============================================================================
Binary file - no diff available.

Propchange: cxf/trunk/rt/rs/description/src/test/resources/javadocs/pet-store-javadoc16.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: cxf/trunk/rt/rs/description/src/test/resources/javadocs/pet-store-javadoc17.jar
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/description/src/test/resources/javadocs/pet-store-javadoc17.jar?rev=1553709&view=auto
==============================================================================
Binary file - no diff available.

Propchange: cxf/trunk/rt/rs/description/src/test/resources/javadocs/pet-store-javadoc17.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream