Repository: camel
Updated Branches:
  refs/heads/master 966846055 -> 7eef2d129


CAMEL-7613 Updated camel-api-component-maven-plugin to support parsing Java8 
Javadoc HTML


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/7eef2d12
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/7eef2d12
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/7eef2d12

Branch: refs/heads/master
Commit: 7eef2d12930c53cbbe97c8528ed6fa6e13a1e1dc
Parents: 9668460
Author: Dhiraj Bokde <dhira...@yahoo.com>
Authored: Wed Jul 23 12:42:21 2014 -0700
Committer: Dhiraj Bokde <dhira...@yahoo.com>
Committed: Wed Jul 23 12:42:38 2014 -0700

----------------------------------------------------------------------
 .../maven/JavadocApiMethodGeneratorMojo.java    | 161 +--------------
 .../org/apache/camel/maven/JavadocParser.java   | 197 +++++++++++++++++++
 .../apache/camel/maven/JavadocParserTest.java   |  55 ++++++
 3 files changed, 253 insertions(+), 160 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/7eef2d12/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
index 572fbf9..dd76a02 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
@@ -19,25 +19,17 @@ package org.apache.camel.maven;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import javax.swing.text.ChangedCharSetException;
-import javax.swing.text.SimpleAttributeSet;
-import javax.swing.text.html.HTML;
 import javax.swing.text.html.parser.DTD;
-import javax.swing.text.html.parser.Parser;
-import javax.swing.text.html.parser.TagElement;
 
 import org.apache.camel.util.component.ApiMethodParser;
-import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
@@ -58,7 +50,6 @@ public class JavadocApiMethodGeneratorMojo extends 
AbstractApiMethodGeneratorMoj
     }
 
     protected static final String DEFAULT_EXCLUDE_PACKAGES = "javax?\\.lang.*";
-    private static final Pattern ARGTYPES_PATTERN = 
Pattern.compile("\\s*([^<\\s,]+\\s*(<[^>]+>)?)\\s*,?");
     private static final Pattern RAW_ARGTYPES_PATTERN = 
Pattern.compile("\\s*([^<\\s,]+)\\s*(<[^>]+>)?\\s*,?");
 
     @Parameter(property = PREFIX + "excludePackages", defaultValue = 
DEFAULT_EXCLUDE_PACKAGES)
@@ -139,9 +130,7 @@ public class JavadocApiMethodGeneratorMojo extends 
AbstractApiMethodGeneratorMoj
                         }
                         final String resultType = getResultType(aClass, name, 
types);
                         if (resultType != null) {
-                            final StringBuilder signature = new 
StringBuilder(resultType);
-                            signature.append(" 
").append(name).append(methodMap.get(method));
-                            result.put(method, signature.toString());
+                            result.put(method, resultType + " " + name + 
methodMap.get(method));
                         }
                     }
                 }
@@ -194,152 +183,4 @@ public class JavadocApiMethodGeneratorMojo extends 
AbstractApiMethodGeneratorMoj
         return result;
     }
 
-    private static class JavadocParser extends Parser {
-        private static final String NON_BREAKING_SPACE = "\u00A0";
-        private String hrefPattern;
-
-        private ParserState parserState;
-        private String methodWithTypes;
-        private StringBuilder methodTextBuilder = new StringBuilder();
-
-        private List<String> methods = new ArrayList<String>();
-        private Map<String, String> methodText = new HashMap<String, String>();
-        private String errorMessage;
-
-        public JavadocParser(DTD dtd, String docPath) {
-            super(dtd);
-            this.hrefPattern = docPath + "#";
-        }
-
-        @Override
-        protected void startTag(TagElement tag) throws ChangedCharSetException 
{
-            super.startTag(tag);
-
-            final HTML.Tag htmlTag = tag.getHTMLTag();
-            if (htmlTag != null) {
-                if (HTML.Tag.A.equals(htmlTag)) {
-                    final SimpleAttributeSet attributes = getAttributes();
-                    final Object name = 
attributes.getAttribute(HTML.Attribute.NAME);
-                    if (name != null) {
-                        final String nameAttr = (String) name;
-                        if (parserState == null && 
"method_summary".equals(nameAttr)) {
-                            parserState = ParserState.METHOD_SUMMARY;
-                        } else if (parserState == ParserState.METHOD_SUMMARY 
&& nameAttr.startsWith("methods_inherited_from_class_")) {
-                            parserState = null;
-                        } else if (parserState == ParserState.METHOD && 
methodWithTypes == null) {
-                            final Object href = 
attributes.getAttribute(HTML.Attribute.HREF);
-                            if (href != null) {
-                                String hrefAttr = (String) href;
-                                if (hrefAttr.contains(hrefPattern)) {
-                                    // unescape HTML
-                                    methodWithTypes = 
unescapeHtml(hrefAttr.substring(hrefAttr.indexOf('#') + 1));
-                                }
-                            }
-                        }
-                    }
-                } else if (parserState == ParserState.METHOD_SUMMARY && 
HTML.Tag.CODE.equals(htmlTag)) {
-                    parserState = ParserState.METHOD;
-                }
-            }
-        }
-
-        private static String unescapeHtml(String htmlString) {
-            String result = 
StringEscapeUtils.unescapeHtml(htmlString).replaceAll(NON_BREAKING_SPACE, " ");
-            try {
-                result = URLDecoder.decode(result, "UTF-8");
-            } catch (UnsupportedEncodingException ignored) {
-
-            }
-            return result;
-        }
-
-        @Override
-        protected void handleEmptyTag(TagElement tag) {
-            if (parserState == ParserState.METHOD && 
HTML.Tag.CODE.equals(tag.getHTMLTag())) {
-                if (methodWithTypes != null) {
-                    // process collected method data
-                    methods.add(methodWithTypes);
-                    this.methodText.put(methodWithTypes, getArgSignature());
-
-                    // clear the text builder for next method
-                    methodTextBuilder.delete(0, methodTextBuilder.length());
-                    methodWithTypes = null;
-                }
-
-                parserState = ParserState.METHOD_SUMMARY;
-            }
-        }
-
-        private String getArgSignature() {
-            final String typeString = 
methodWithTypes.substring(methodWithTypes.indexOf('(') + 1, 
methodWithTypes.indexOf(')'));
-            if (typeString.isEmpty()) {
-                return "()";
-            }
-
-            // split types list
-            final List<String> typeList = new ArrayList<String>();
-            final Matcher typeMatcher = ARGTYPES_PATTERN.matcher(typeString);
-            while (typeMatcher.find()) {
-                typeList.add(typeMatcher.group(1).replaceAll(" ", ""));
-            }
-
-            // unescape HTML method text
-            final String plainText = 
unescapeHtml(methodTextBuilder.toString());
-            final String argsString = 
plainText.substring(plainText.indexOf('(') + 1, plainText.indexOf(')'));
-            final Matcher argMatcher = 
ApiMethodParser.ARGS_PATTERN.matcher(argsString);
-            final List<String> argNames = new ArrayList<String>();
-            while (argMatcher.find()) {
-                argNames.add(argMatcher.group(3));
-            }
-
-            // make sure number of types and names match
-            final int nTypes = typeList.size();
-            if (nTypes != argNames.size()) {
-                throw new IllegalArgumentException("Unexpected Javadoc error, 
different number of arg types and names");
-            }
-
-            final String[] names = argNames.toArray(new String[nTypes]);
-            final StringBuilder builder = new StringBuilder("(");
-            int i = 0;
-            for (String type : typeList) {
-                // split on space or non-breaking space
-                builder.append(type).append(' ').append(names[i++]);
-                if (i < nTypes) {
-                    builder.append(',');
-                }
-            }
-            builder.append(')');
-            return builder.toString();
-        }
-
-        @Override
-        protected void handleText(char[] text) {
-            if (parserState == ParserState.METHOD && methodWithTypes != null) {
-                methodTextBuilder.append(text);
-            }
-        }
-
-        @Override
-        protected void handleError(int ln, String msg) {
-            if (msg.startsWith("exception ")) {
-                this.errorMessage = "Exception parsing Javadoc line " + ln + 
": " + msg;
-            }
-        }
-
-        private String getErrorMessage() {
-            return errorMessage;
-        }
-
-        private List<String> getMethods() {
-            return methods;
-        }
-
-        private Map<String, String> getMethodText() {
-            return methodText;
-        }
-    }
-
-    private static enum ParserState {
-        METHOD_SUMMARY, METHOD;
-    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/7eef2d12/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocParser.java
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocParser.java
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocParser.java
new file mode 100644
index 0000000..24e4489
--- /dev/null
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocParser.java
@@ -0,0 +1,197 @@
+/**
+ * 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.camel.maven;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.swing.text.ChangedCharSetException;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.parser.DTD;
+import javax.swing.text.html.parser.Parser;
+import javax.swing.text.html.parser.TagElement;
+
+import org.apache.commons.lang.StringEscapeUtils;
+
+/**
+ * Parses Javadoc HTML to get Method Signatures from Method Sumary. Supports 
Java 6, 7 and 8 Javadoc formats.
+ */
+public class JavadocParser extends Parser {
+
+    private static final String NON_BREAKING_SPACE = "\u00A0";
+
+    private final String hrefPattern;
+
+    private ParserState parserState;
+    private String methodWithTypes;
+    private StringBuilder methodTextBuilder = new StringBuilder();
+
+    private List<String> methods = new ArrayList<String>();
+    private Map<String, String> methodText = new HashMap<String, String>();
+    private String errorMessage;
+
+    public JavadocParser(DTD dtd, String docPath) {
+        super(dtd);
+        this.hrefPattern = docPath + "#";
+        parserState = ParserState.INIT;
+    }
+
+    public void reset() {
+        parserState = ParserState.INIT;
+
+        methodWithTypes = null;
+        methodTextBuilder = new StringBuilder();
+
+        methods.clear();
+        methodText.clear();
+
+        errorMessage = null;
+    }
+
+    @Override
+    protected void startTag(TagElement tag) throws ChangedCharSetException {
+        super.startTag(tag);
+
+        final HTML.Tag htmlTag = tag.getHTMLTag();
+        if (htmlTag != null) {
+            if (HTML.Tag.A.equals(htmlTag)) {
+                final SimpleAttributeSet attributes = getAttributes();
+                final Object name = 
attributes.getAttribute(HTML.Attribute.NAME);
+                if (name != null) {
+                    final String nameAttr = (String) name;
+                    if (parserState == ParserState.INIT
+                        && ("method_summary".equals(nameAttr) || 
"method.summary".equals(nameAttr))) {
+                        parserState = ParserState.METHOD_SUMMARY;
+                    } else if (parserState == ParserState.METHOD) {
+                        if (methodWithTypes == null) {
+
+                            final String hrefAttr = (String) 
attributes.getAttribute(HTML.Attribute.HREF);
+                            if (hrefAttr != null && 
hrefAttr.contains(hrefPattern)) {
+
+                                // unescape HTML
+                                String methodSignature = 
hrefAttr.substring(hrefAttr.indexOf('#') + 1);
+                                final int firstHyphen = 
methodSignature.indexOf('-');
+                                if (firstHyphen != -1) {
+                                    final int lastHyphen = 
methodSignature.lastIndexOf('-');
+                                    methodSignature = 
methodSignature.substring(0, firstHyphen) + "("
+                                        + 
methodSignature.substring(firstHyphen + 1, lastHyphen) + ")";
+                                    methodSignature = 
methodSignature.replaceAll("-", ",");
+                                }
+                                // support varargs
+                                if (methodSignature.contains("...)")) {
+                                    methodSignature = 
methodSignature.replaceAll("\\.\\.\\.\\)", "[])");
+                                }
+                                // map Java8 array types
+                                if (methodSignature.contains(":A")) {
+                                    methodSignature = 
methodSignature.replaceAll(":A", "[]");
+                                }
+                                methodWithTypes = 
unescapeHtml(methodSignature);
+                            }
+                        } else {
+                            final String title = (String) 
attributes.getAttribute(HTML.Attribute.TITLE);
+                            if (title != null) {
+                                // append package name to type name text
+                                
methodTextBuilder.append(title.substring(title.lastIndexOf(' '))).append('.');
+                            }
+                        }
+                    }
+                }
+            } else if (parserState == ParserState.METHOD_SUMMARY && 
HTML.Tag.CODE.equals(htmlTag)) {
+                parserState = ParserState.METHOD;
+            }
+        }
+    }
+
+    private static String unescapeHtml(String htmlString) {
+        String result = 
StringEscapeUtils.unescapeHtml(htmlString).replaceAll(NON_BREAKING_SPACE, " ");
+        try {
+            result = URLDecoder.decode(result, "UTF-8");
+        } catch (UnsupportedEncodingException ignored) {
+
+        }
+        return result;
+    }
+
+    @Override
+    protected void handleEmptyTag(TagElement tag) {
+        if (parserState == ParserState.METHOD && 
HTML.Tag.CODE.equals(tag.getHTMLTag())) {
+            if (methodWithTypes != null) {
+                // process collected method data
+                methods.add(methodWithTypes);
+                this.methodText.put(methodWithTypes, getArgSignature());
+
+                // clear the text builder for next method
+                methodTextBuilder.delete(0, methodTextBuilder.length());
+                methodWithTypes = null;
+            }
+
+            parserState = ParserState.METHOD_SUMMARY;
+        } else if (parserState == ParserState.METHOD_SUMMARY && 
HTML.Tag.TABLE.equals(tag.getHTMLTag())) {
+            // end of method summary table
+            parserState = ParserState.INIT;
+        }
+    }
+
+    private String getArgSignature() {
+        final String typeString = 
methodWithTypes.substring(methodWithTypes.indexOf('(') + 1, 
methodWithTypes.indexOf(')'));
+        if (typeString.isEmpty()) {
+            return "()";
+        }
+
+        // unescape HTML method text
+        String plainText = unescapeHtml(methodTextBuilder.toString());
+        // support varargs
+        if (plainText.contains("...")) {
+            plainText = plainText.replaceAll("\\.\\.\\.", "[]");
+        }
+        return plainText.substring(plainText.indexOf('('), 
plainText.indexOf(')') + 1);
+    }
+
+    @Override
+    protected void handleText(char[] text) {
+        if (parserState == ParserState.METHOD && methodWithTypes != null) {
+            methodTextBuilder.append(text);
+        }
+    }
+
+    @Override
+    protected void handleError(int ln, String msg) {
+        if (msg.startsWith("exception ")) {
+            this.errorMessage = "Exception parsing Javadoc line " + ln + ": " 
+ msg;
+        }
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public List<String> getMethods() {
+        return methods;
+    }
+
+    public Map<String, String> getMethodText() {
+        return methodText;
+    }
+
+    private static enum ParserState {
+        INIT, METHOD_SUMMARY, METHOD
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/7eef2d12/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/JavadocParserTest.java
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/JavadocParserTest.java
 
b/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/JavadocParserTest.java
new file mode 100644
index 0000000..c98812d
--- /dev/null
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/JavadocParserTest.java
@@ -0,0 +1,55 @@
+/**
+ * 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.camel.maven;
+
+import java.io.InputStreamReader;
+import java.net.URL;
+import javax.swing.text.html.parser.DTD;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test JavadocParser using {@link java.lang.String} javadoc for Java 6, 7 and 
8.
+ */
+public class JavadocParserTest extends Assert {
+
+    private static final String JAVA6_STRING = 
"http://docs.oracle.com/javase/6/docs/api/java/lang/String.html";;
+    private static final String JAVA7_STRING = 
"http://docs.oracle.com/javase/7/docs/api/java/lang/String.html";;
+    private static final String JAVA8_STRING = 
"http://docs.oracle.com/javase/8/docs/api/java/lang/String.html";;
+
+    @Test
+    public void testGetMethods() throws Exception {
+        final DTD dtd = DTD.getDTD("html.dtd");
+        final String javaDocPath = String.class.getName().replaceAll("\\.", 
"/") + ".html";
+        final JavadocParser htmlParser = new JavadocParser(dtd, javaDocPath);
+
+        htmlParser.parse(new InputStreamReader(new 
URL(JAVA6_STRING).openStream(), "UTF-8"));
+        assertNull("Java6 getErrorMessage", htmlParser.getErrorMessage());
+        assertFalse("Java6 getMethods", htmlParser.getMethods().isEmpty());
+        htmlParser.reset();
+
+        htmlParser.parse(new InputStreamReader(new 
URL(JAVA7_STRING).openStream(), "UTF-8"));
+        assertNull("Java7 getErrorMessage", htmlParser.getErrorMessage());
+        assertFalse("Java7 getMethods", htmlParser.getMethods().isEmpty());
+        htmlParser.reset();
+
+        htmlParser.parse(new InputStreamReader(new 
URL(JAVA8_STRING).openStream(), "UTF-8"));
+        assertNull("Java8 getErrorMessage", htmlParser.getErrorMessage());
+        assertFalse("Java8 getMethods", htmlParser.getMethods().isEmpty());
+    }
+}

Reply via email to