This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 4ca51e34fb5f1ebf44147045998281ca568855db
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Fri Jun 21 13:12:06 2019 +0200

    CAMEL-13663: camel-main-maven-plugin to generte spring-boot tooling 
metadata to fool Java editors to have code completions for Camel Main 
application.properties files.
---
 catalog/camel-main-maven-plugin/pom.xml            |   7 ++
 .../src/main/docs/camel-main-maven-plugin.adoc     |   1 +
 .../org/apache/camel/maven/GenerateHelper.java     | 111 +++++++++++++++++++++
 .../java/org/apache/camel/maven/GenerateMojo.java  |  77 ++++++++------
 examples/camel-example-main-artemis/pom.xml        |   4 +-
 .../META-INF/spring-configuration-metadata.json    |   6 +-
 .../src/main/resources/application.properties      |   2 +
 7 files changed, 171 insertions(+), 37 deletions(-)

diff --git a/catalog/camel-main-maven-plugin/pom.xml 
b/catalog/camel-main-maven-plugin/pom.xml
index f5e0d54..dbe295b 100644
--- a/catalog/camel-main-maven-plugin/pom.xml
+++ b/catalog/camel-main-maven-plugin/pom.xml
@@ -119,6 +119,13 @@
             <version>${project.version}</version>
         </dependency>
 
+        <!-- java source parser -->
+        <dependency>
+            <groupId>org.jboss.forge.roaster</groupId>
+            <artifactId>roaster-jdt</artifactId>
+            <version>${roaster-version}</version>
+        </dependency>
+
         <!-- logging -->
         <dependency>
             <groupId>org.apache.logging.log4j</groupId>
diff --git 
a/catalog/camel-main-maven-plugin/src/main/docs/camel-main-maven-plugin.adoc 
b/catalog/camel-main-maven-plugin/src/main/docs/camel-main-maven-plugin.adoc
index 34f9007..b904168 100644
--- a/catalog/camel-main-maven-plugin/src/main/docs/camel-main-maven-plugin.adoc
+++ b/catalog/camel-main-maven-plugin/src/main/docs/camel-main-maven-plugin.adoc
@@ -169,6 +169,7 @@ The maven plugin *generate* goal supports the following 
options which can be con
 | logUnmapped | false | When autowiring has detected multiple implementations 
(2 or more) of a given interface, which cannot be mapped, should they be logged 
so you can see and add manual mapping if needed.
 | downloadVersion | true | Whether to allow downloading Camel catalog version 
from the internet.
   This is needed if the project * uses a different Camel version than this 
plugin is using by default.
+| downloadSourceJars | true | Whether to allow downloading -source JARs when 
generating spring boot tooling to include javadoc as description for discovered 
options.
 | exclude | | To exclude autowiring specific properties with these key names. 
You can also configure a single entry and separate the excludes with comma.
 | include | | To include autowiring specific properties with these key names. 
You can also configure a single entry and separate the includes with comma.
 | mappings | | To setup special mappings between known types as key=value 
pairs. You can also configure a single entry and separate the mappings with 
comma.
diff --git 
a/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/GenerateHelper.java
 
b/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/GenerateHelper.java
new file mode 100644
index 0000000..9f6f8ef
--- /dev/null
+++ 
b/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/GenerateHelper.java
@@ -0,0 +1,111 @@
+/*
+ * 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;
+
+public final class GenerateHelper {
+
+    private static final String VALID_CHARS = ".,-='/\\!&%():;#${}";
+
+    private GenerateHelper() {
+    }
+
+    /**
+     * Sanitizes the javadoc to removed invalid characters so it can be used 
as json description
+     *
+     * @param javadoc  the javadoc
+     * @return the text that is valid as json
+     */
+    public static String sanitizeDescription(String javadoc, boolean summary) {
+        if (javadoc == null || javadoc.isEmpty()) {
+            return null;
+        }
+
+        // lets just use what java accepts as identifiers
+        StringBuilder sb = new StringBuilder();
+
+        // split into lines
+        String[] lines = javadoc.split("\n");
+
+        boolean first = true;
+        for (String line : lines) {
+            line = line.trim();
+
+            if (line.startsWith("**")) {
+                continue;
+            }
+            // remove leading javadoc *
+            if (line.startsWith("*")) {
+                line = line.substring(1);
+                line = line.trim();
+            }
+
+            // terminate if we reach @param, @return or @deprecated as we only 
want the javadoc summary
+            if (line.startsWith("@param") || line.startsWith("@return") || 
line.startsWith("@deprecated")) {
+                break;
+            }
+
+            // skip lines that are javadoc references
+            if (line.startsWith("@")) {
+                continue;
+            }
+
+            // remove all XML tags
+            line = line.replaceAll("<.*?>", "");
+
+            // remove all inlined javadoc links, eg such as {@link 
org.apache.camel.spi.Registry}
+            // use #? to remove leading # in case its a local reference
+            line = line.replaceAll("\\{\\@\\w+\\s#?([\\w.#(\\d,)]+)\\}", "$1");
+
+            // we are starting from a new line, so add a whitespace
+            if (!first) {
+                sb.append(' ');
+            }
+
+            // create a new line
+            StringBuilder cb = new StringBuilder();
+            for (char c : line.toCharArray()) {
+                if (Character.isJavaIdentifierPart(c) || 
VALID_CHARS.indexOf(c) != -1) {
+                    cb.append(c);
+                } else if (Character.isWhitespace(c)) {
+                    // always use space as whitespace, also for line feeds etc
+                    cb.append(' ');
+                }
+            }
+
+            // append data
+            String s = cb.toString().trim();
+            sb.append(s);
+
+            boolean empty = s.isEmpty();
+            boolean endWithDot = s.endsWith(".");
+            boolean haveText = sb.length() > 0;
+
+            if (haveText && summary && (empty || endWithDot)) {
+                // if we only want a summary, then skip at first empty line we 
encounter, or if the sentence ends with a dot
+                break;
+            }
+
+            first = false;
+        }
+
+        // remove double whitespaces, and trim
+        String s = sb.toString();
+        s = s.replaceAll("\\s+", " ");
+        return s.trim();
+    }
+
+}
diff --git 
a/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
 
b/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
index dc460e6..158fe84 100644
--- 
a/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
+++ 
b/catalog/camel-main-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
@@ -1,13 +1,13 @@
-/**
+/*
  * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
+ *
+ *      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.
@@ -23,23 +23,16 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.net.JarURLConnection;
-import java.net.URL;
 import java.util.ArrayList;
-import java.util.Enumeration;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.logging.FileHandler;
 import java.util.stream.Collectors;
 
 import org.apache.camel.maven.model.AutowireData;
 import org.apache.camel.maven.model.SpringBootData;
 import org.apache.camel.support.IntrospectionSupport;
 import org.apache.camel.support.PatternHelper;
-import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.OrderedProperties;
 import org.apache.camel.util.StringHelper;
@@ -50,6 +43,11 @@ import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
 
+import org.jboss.forge.roaster.Roaster;
+import org.jboss.forge.roaster.model.source.JavaClassSource;
+import org.jboss.forge.roaster.model.source.MethodSource;
+
+import static org.apache.camel.maven.GenerateHelper.sanitizeDescription;
 import static org.apache.camel.util.StringHelper.camelCaseToDash;
 
 /**
@@ -71,6 +69,13 @@ public class GenerateMojo extends AbstractMainMojo {
     protected boolean springBootEnabled;
 
     /**
+     * Whether to allow downloading -source JARs when generating spring boot 
tooling to include
+     * javadoc as description for discovered options.
+     */
+    @Parameter(property = "camel.downloadSourceJars", defaultValue = "true")
+    protected boolean downloadSourceJars;
+
+    /**
      * When autowiring has detected multiple implementations (2 or more) of a 
given interface, which
      * cannot be mapped, should they be logged so you can see and add manual 
mapping if needed.
      */
@@ -165,12 +170,12 @@ public class GenerateMojo extends AbstractMainMojo {
                         Set<Class<?>> classes = 
reflections.getSubTypesOf(clazz);
                         // filter classes (must not be interfaces, must be 
public, must not be abstract, must be top level) and also a valid autowire class
                         classes = classes.stream().filter(
-                                c -> !c.isInterface()
-                                        && Modifier.isPublic(c.getModifiers())
-                                        && 
!Modifier.isAbstract(c.getModifiers())
-                                        && c.getEnclosingClass() == null
-                                        && isValidAutowireClass(c))
-                                .collect(Collectors.toSet());
+                            c -> !c.isInterface()
+                            && Modifier.isPublic(c.getModifiers())
+                            && !Modifier.isAbstract(c.getModifiers())
+                            && c.getEnclosingClass() == null
+                            && isValidAutowireClass(c))
+                            .collect(Collectors.toSet());
                         Class best = chooseBestKnownType(componentName, name, 
clazz, classes, mappingProperties);
                         if (best != null) {
                             key = "camel.component." + componentName + "." + 
dash;
@@ -186,17 +191,18 @@ public class GenerateMojo extends AbstractMainMojo {
                                 // sort the setters
                                 setters.sort((o1, o2) -> 
o1.getName().compareToIgnoreCase(o2.getName()));
 
-                                String javaSource = null;
-                                if (!setters.isEmpty()) {
+                                JavaClassSource javaClassSource = null;
+                                if (downloadSourceJars && !setters.isEmpty()) {
                                     String path = best.getName().replace('.', 
'/') + ".java";
                                     getLog().debug("Loading Java source: " + 
path);
 
                                     InputStream is = 
getSourcesClassLoader().getResourceAsStream(path);
                                     if (is != null) {
-                                        javaSource = IOHelper.loadText(is);
+                                        String text = IOHelper.loadText(is);
                                         IOHelper.close(is);
+                                        javaClassSource = (JavaClassSource) 
Roaster.parse(text);
                                     }
-                                    getLog().info("Loaded source code: " + 
javaSource);
+                                    getLog().debug("Loaded source code: " + 
clazz);
                                 }
 
                                 for (Method m : setters) {
@@ -208,8 +214,17 @@ public class GenerateMojo extends AbstractMainMojo {
                                     getLog().debug("Spring Boot option: " + 
bootKey);
 
                                     // find the setter method and grab the 
javadoc
+                                    String desc = 
extractJavaDocFromMethod(javaClassSource, m);
+                                    if (desc == null) {
+                                        desc = "";
+                                    } else {
+                                        desc = sanitizeDescription(desc, 
false);
+                                        if (!desc.endsWith(".")) {
+                                            desc += ". ";
+                                        }
+                                    }
+                                    desc += "Auto discovered option from 
class: " + best.getName() + " to set the option via setter: " + m.getName();
 
-                                    String desc = "Auto discovered option from 
class: " + best.getName() + " to set the option via setter: " + m.getName();
                                     springBootData.add(new 
SpringBootData(bootKey, springBootJavaType(bootJavaType), desc, sourceType, 
null));
                                 }
                             }
@@ -465,15 +480,15 @@ public class GenerateMojo extends AbstractMainMojo {
         }
     }
 
-    public static void main(String[] args) throws Exception {
-        JarFile jar = new 
JarFile("/Users/davsclaus/.m2/repository/org/springframework/spring-jms/5.1.8.RELEASE/spring-jms-5.1.8.RELEASE-sources.jar");
-        System.out.println(jar);
-        JarEntry en = 
jar.getJarEntry("org/springframework/jms/connection/CachingConnectionFactory.java");
-        System.out.println(en);
-        InputStream is = jar.getInputStream(en);
-        String source = IOHelper.loadText(is);
-        IOHelper.close(is);
-        System.out.println(source);
+    private static String extractJavaDocFromMethod(JavaClassSource clazz, 
Method method) {
+        if (clazz == null) {
+            return null;
+        }
+        MethodSource ms = clazz.getMethod(method.getName(), 
method.getParameterTypes()[0]);
+        if (ms != null) {
+            return ms.getJavaDoc().getText();
+        }
+        return null;
     }
 
 }
diff --git a/examples/camel-example-main-artemis/pom.xml 
b/examples/camel-example-main-artemis/pom.xml
index 5d0ddc0..c918bb2 100644
--- a/examples/camel-example-main-artemis/pom.xml
+++ b/examples/camel-example-main-artemis/pom.xml
@@ -40,12 +40,10 @@
     <dependencies>
 
         <!-- to have spring boot tooling support in IDEA you need spring-boot 
JARs on the classpath -->
-<!--
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-spring-boot-starter</artifactId>
         </dependency>
--->
 
         <dependency>
             <groupId>org.apache.camel</groupId>
@@ -113,7 +111,7 @@
                 <artifactId>camel-main-maven-plugin</artifactId>
                 <version>${project.version}</version>
                 <configuration>
-                    <logClasspath>true</logClasspath>
+                    <logClasspath>false</logClasspath>
                     <!-- lets show which options are unmapped -->
                     <!-- <logUnmapped>true</logUnmapped> -->
                     <!-- just include only the jms component -->
diff --git 
a/examples/camel-example-main-artemis/src/main/resources/META-INF/spring-configuration-metadata.json
 
b/examples/camel-example-main-artemis/src/main/resources/META-INF/spring-configuration-metadata.json
index 06960b3..c771da6 100644
--- 
a/examples/camel-example-main-artemis/src/main/resources/META-INF/spring-configuration-metadata.json
+++ 
b/examples/camel-example-main-artemis/src/main/resources/META-INF/spring-configuration-metadata.json
@@ -787,13 +787,13 @@
       "name": "camel.component.jms.connection-factory.cache-consumers",
       "type": "java.lang.Boolean",
       "sourceType": 
"org.springframework.jms.connection.CachingConnectionFactory",
-      "description": "Auto discovered option from class: 
org.springframework.jms.connection.CachingConnectionFactory to set the option 
via setter: setCacheConsumers"
+      "description": "Specify whether to cache JMS MessageConsumers per JMS 
Session instance(more specifically: one MessageConsumer per Destination, 
selector Stringand Session). Note that durable subscribers will only be cached 
untillogical closing of the Session handle.Default is true. Switch this to 
false in order to alwaysrecreate MessageConsumers on demand.Auto discovered 
option from class: org.springframework.jms.connection.CachingConnectionFactory 
to set the option via setter: setC [...]
     },
     {
       "name": "camel.component.jms.connection-factory.cache-producers",
       "type": "java.lang.Boolean",
       "sourceType": 
"org.springframework.jms.connection.CachingConnectionFactory",
-      "description": "Auto discovered option from class: 
org.springframework.jms.connection.CachingConnectionFactory to set the option 
via setter: setCacheProducers"
+      "description": "Specify whether to cache JMS MessageProducers per JMS 
Session instance(more specifically: one MessageProducer per Destination and 
Session).Default is true. Switch this to false in order to alwaysrecreate 
MessageProducers on demand.Auto discovered option from class: 
org.springframework.jms.connection.CachingConnectionFactory to set the option 
via setter: setCacheProducers"
     },
     {
       "name": "camel.component.jms.connection-factory.client-id",
@@ -817,7 +817,7 @@
       "name": "camel.component.jms.connection-factory.session-cache-size",
       "type": "java.lang.Integer",
       "sourceType": 
"org.springframework.jms.connection.CachingConnectionFactory",
-      "description": "Auto discovered option from class: 
org.springframework.jms.connection.CachingConnectionFactory to set the option 
via setter: setSessionCacheSize"
+      "description": "Specify the desired size for the JMS Session cache (per 
JMS Session type).This cache size is the maximum limit for the number of cached 
Sessionsper session acknowledgement type (auto, client, dups_ok, transacted).As 
a consequence, the actual number of cached Sessions may be up tofour times as 
high as the specified value - in the unlikely caseof mixing and matching 
different acknowledgement types.Default is 1: caching a single Session, 
(re-)creating further ones onde [...]
     },
     {
       "name": 
"camel.component.jms.connection-factory.target-connection-factory",
diff --git 
a/examples/camel-example-main-artemis/src/main/resources/application.properties 
b/examples/camel-example-main-artemis/src/main/resources/application.properties
index 309db5c..14ea669 100644
--- 
a/examples/camel-example-main-artemis/src/main/resources/application.properties
+++ 
b/examples/camel-example-main-artemis/src/main/resources/application.properties
@@ -29,6 +29,8 @@ camel.main.jmx-enabled = false
 # which contains some additional autowires so we only need here to specify the 
URL to the broker
 camel.component.jms.connection-factory.brokerURL=tcp://localhost:61616
 
+camel.component.jms.connection-factory.cl
+
 # in case you want to use Spring's CachingConnectionFactory, you can configure 
it as follows:
 # (then you don't need the camel-main-maven-plugin, as you can explicit 
configure it all here)
 ### 
camel.component.jms.connectionFactory=#class:org.springframework.jms.connection.CachingConnectionFactory

Reply via email to