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

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

commit 844167a19c3ac041135fa5ec4aab191354a0f2b5
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Mon Jul 16 20:02:53 2018 +0200

    CAMEL-12644: Generate spring boot auto configuration in the docs.
---
 .../camel-jdbc/src/main/docs/jdbc-component.adoc   |  90 ++++-----
 platforms/spring-boot/components-starter/pom.xml   |  18 ++
 ...pdateSpringBootAutoConfigurationReadmeMojo.java | 214 +++++++++++++++++++++
 .../model/SpringBootAutoConfigureOptionModel.java  | 112 +++++++++++
 .../spring-boot-auto-configure-options.mvel        |  15 ++
 5 files changed, 406 insertions(+), 43 deletions(-)

diff --git a/components/camel-jdbc/src/main/docs/jdbc-component.adoc 
b/components/camel-jdbc/src/main/docs/jdbc-component.adoc
index 1fdb4ad..3ac2713 100644
--- a/components/camel-jdbc/src/main/docs/jdbc-component.adoc
+++ b/components/camel-jdbc/src/main/docs/jdbc-component.adoc
@@ -12,35 +12,32 @@ spring-jdbc.
 Maven users will need to add the following dependency to their `pom.xml`
 for this component:
 
-[source,java]
-------------------------------------------------------------
+[source,xml]
+----
 <dependency>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-jdbc</artifactId>
     <version>x.x.x</version>
     <!-- use the same version as your Camel core version -->
 </dependency>
-------------------------------------------------------------
+----
 
 This component can only be used to define producer endpoints, which
 means that you cannot use the JDBC component in a `from()` statement.
 
-### URI format
+=== URI format
 
-[source,java]
------------------------------
+[source,text]
+----
 jdbc:dataSourceName[?options]
------------------------------
+----
 
 This component only supports producer endpoints.
 
 You can append query options to the URI in the following format,
 `?option=value&option=value&...`
 
-### Options
-
-
-
+=== Options
 
 // component options: START
 The JDBC component supports 2 options, which are listed below.
@@ -101,9 +98,27 @@ with the following path and query parameters:
 |===
 // endpoint options: END
 
+// spring-boot-auto-configure options: START
+=== Spring Boot Auto-Configuration
+
+
+The component supports 3 options, which are listed below.
+
 
 
-### Result
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *camel.component.jdbc.data-source* | To use the DataSource instance instead 
of looking up the data source by
+ name from the registry. The option is a javax.sql.DataSource type. |  | String
+| *camel.component.jdbc.enabled* | Enable jdbc component | true | boolean
+| *camel.component.jdbc.resolve-property-placeholders* | Whether the component 
should resolve property placeholders on itself when
+ starting. Only properties which are of String type can use property
+ placeholders. | true | boolean
+|===
+// spring-boot-auto-configure options: END
+
+=== Result
 
 By default the result is returned in the OUT body as an
 `ArrayList<HashMap<String, Object>>`. The `List` object contains the
@@ -114,10 +129,10 @@ the result.
 *Note:* This component fetches `ResultSetMetaData` to be able to return
 the column name as the key in the `Map`.
 
-#### Message Headers
+==== Message Headers
 
 [width="100%",cols="10%,90%",options="header",]
-|=======================================================================
+|===
 |Header |Description
 
 |`CamelJdbcRowCount` |If the query is a `SELECT`, query the row count is 
returned in this OUT
@@ -136,9 +151,9 @@ type.
 
 |`CamelJdbcParametes` |*Camel 2.12:* A `java.util.Map` which has the headers 
to be used if
 `useHeadersAsParameters` has been enabled.
-|=======================================================================
+|===
 
-### Generated keys
+=== Generated keys
 
 *Available as of Camel 2.10*
 
@@ -155,7 +170,7 @@ test].
 
 Using generated keys does not work with together with named parameters.
 
-### Using named parameters
+=== Using named parameters
 
 *Available as of Camel 2.12*
 
@@ -167,18 +182,18 @@ Notice in the example above we set two headers with 
constant value +
  for the named parameters:
 
 [source,java]
-----------------------------------------------------------------------------------------
+----
   from("direct:projects")
      .setHeader("lic", constant("ASF"))
      .setHeader("min", constant(123))
      .setBody("select * from projects where license = :?lic and id > :?min 
order by id")
      .to("jdbc:myDataSource?useHeadersAsParameters=true")
-----------------------------------------------------------------------------------------
+----
 
 You can also store the header values in a `java.util.Map` and store the
 map on the headers with the key `CamelJdbcParameters`.
 
-### Samples
+=== Samples
 
 In the following example, we fetch the rows from the customer table.
 
@@ -198,12 +213,8 @@ If you want to work on the rows one by one instead of the 
entire
 ResultSet at once you need to use the Splitter EIP
 such as:
 
-In Camel 2.13.x or older
-
-In Camel 2.14.x or newer
-
 [source,java]
--------------------------------------------------------------------------------------------------
+----
 from("direct:hello")
 // here we split the data from the testdb into new messages one by one
 // so the mock endpoint will receive a message per row in the table
@@ -212,9 +223,9 @@ from("direct:hello")
 .to("jdbc:testdb?outputType=StreamList")
   .split(body()).streaming()
   .to("mock:result");
--------------------------------------------------------------------------------------------------
+----
 
-### Sample - Polling the database every minute
+=== Sample - Polling the database every minute
 
 If we want to poll a database using the JDBC component, we need to
 combine it with a polling scheduler such as the <<timer-component,Timer>>
@@ -222,11 +233,14 @@ or <<quartz-component,Quartz>> etc. In the following 
example, we retrieve
 data from the database every 60 seconds:
 
 [source,java]
-------------------------------------------------------------------------------------------------------------------------------
-from("timer://foo?period=60000").setBody(constant("select * from 
customer")).to("jdbc:testdb").to("activemq:queue:customers");
-------------------------------------------------------------------------------------------------------------------------------
+----
+from("timer://foo?period=60000")
+  .setBody(constant("select * from customer"))
+  .to("jdbc:testdb")
+  .to("activemq:queue:customers");
+----
 
-### Sample - Move Data Between Data Sources +
+=== Sample - Move Data Between Data Sources
 
 A common use case is to query for data, process it and move it to
 another data source (ETL operations). In the following example, we
@@ -234,7 +248,7 @@ retrieve new customer records from the source table every 
hour,
 filter/transform them and move them to a destination table:
 
 [source,java]
-------------------------------------------------------------------------------------------------
+----
 from("timer://MoveNewCustomersEveryHour?period=3600000")
     .setBody(constant("select * from customer where create_time > 
(sysdate-1/24)"))
     .to("jdbc:testdb")
@@ -242,15 +256,5 @@ from("timer://MoveNewCustomersEveryHour?period=3600000")
         .process(new MyCustomerProcessor()) //filter/transform results as 
needed
         .setBody(simple("insert into processed_customer 
values('${body[ID]}','${body[NAME]}')"))
         .to("jdbc:testdb");
-------------------------------------------------------------------------------------------------
-
- 
-
-### See Also
-
-* Configuring Camel
-* Component
-* Endpoint
-* Getting Started
+----
 
-* <<sql-component,SQL>>
diff --git a/platforms/spring-boot/components-starter/pom.xml 
b/platforms/spring-boot/components-starter/pom.xml
index 5b0ee13..0e65b06 100644
--- a/platforms/spring-boot/components-starter/pom.xml
+++ b/platforms/spring-boot/components-starter/pom.xml
@@ -77,6 +77,24 @@
           <failIfNoTests>false</failIfNoTests>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-package-maven-plugin</artifactId>
+        <version>${project.version}</version>
+        <configuration>
+          <!-- set to true to make build fail fast if missing documentation in 
docs files -->
+          <failFast>false</failFast>
+        </configuration>
+        <executions>
+          <execution>
+            <id>readme</id>
+            <goals>
+              <goal>update-spring-boot-auto-configuration-readme</goal>
+            </goals>
+            <phase>package</phase>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
   <!-- WARNING: do not edit the modules section, it is update automatically by 
the camel-package plugin -->
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateSpringBootAutoConfigurationReadmeMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateSpringBootAutoConfigurationReadmeMojo.java
new file mode 100644
index 0000000..8ebb68f
--- /dev/null
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateSpringBootAutoConfigurationReadmeMojo.java
@@ -0,0 +1,214 @@
+/**
+ * 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>
+ * 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.packaging;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import 
org.apache.camel.maven.packaging.model.SpringBootAutoConfigureOptionModel;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.json.simple.DeserializationException;
+import org.json.simple.JsonArray;
+import org.json.simple.JsonObject;
+import org.json.simple.Jsoner;
+import org.mvel2.templates.TemplateRuntime;
+import org.sonatype.plexus.build.incremental.BuildContext;
+
+import static org.apache.camel.maven.packaging.PackageHelper.loadText;
+import static org.apache.camel.maven.packaging.PackageHelper.writeText;
+
+/**
+ * Generate or updates the component/dataformat/language/eip readme.md and 
.adoc files in the project root directory
+ * to include spring boot auto configuration options.
+ *
+ * @goal update-spring-boot-auto-configuration-readme
+ */
+public class UpdateSpringBootAutoConfigurationReadmeMojo extends AbstractMojo {
+
+    /**
+     * The maven project.
+     *
+     * @parameter property="project"
+     * @required
+     * @readonly
+     */
+    protected MavenProject project;
+
+    /**
+     * The project build directory
+     *
+     * @parameter default-value="${project.build.directory}"
+     */
+    protected File buildDir;
+
+    /**
+     * The documentation directory
+     *
+     * @parameter default-value="${basedir}/../../../../components/"
+     */
+    protected File componentsDir;
+
+    /**
+     * Whether to fail the build fast if any Warnings was detected.
+     *
+     * @parameter
+     */
+    protected Boolean failFast;
+
+    /**
+     * build context to check changed files and mark them for refresh (used for
+     * m2e compatibility)
+     *
+     * @component
+     * @readonly
+     */
+    private BuildContext buildContext;
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        try {
+            executeStarter(project.getBasedir());
+        } catch (Exception e) {
+            throw new MojoFailureException("Error processing 
spring-configuration-metadata.json", e);
+        }
+    }
+
+    private void executeStarter(File starter) throws Exception {
+        File jsonFile = new File(buildDir, 
"classes/META-INF/spring-configuration-metadata.json");
+
+        // only if there is components we should update the documentation files
+        if (jsonFile.exists()) {
+            getLog().info("Processing file: " + jsonFile);
+            Object js = Jsoner.deserialize(new FileReader(jsonFile));
+            if (js != null) {
+                String name = starter.getName();
+                // skip camel-  and -starter in the end
+                String componentName = name.substring(6, name.length() - 8);
+                getLog().debug("Camel component: " + componentName);
+                File docFolder = new File(componentsDir, "camel-" + 
componentName + "/src/main/docs/");
+                // update all adoc files (as it may be component, language, 
data-format or just other kind)
+                File[] docFiles = docFolder.listFiles((f) -> 
f.getName().startsWith(componentName) && f.getName().endsWith(".adoc"));
+                if (docFiles != null && docFiles.length > 0) {
+                    List models = parseSpringBootAutoConfigreModels(jsonFile);
+                    String options = templateAutoConfigurationOptions(models);
+                    for (File docFile : docFiles) {
+                        boolean updated = updateAutoConfigureOptions(docFile, 
options);
+                        if (updated) {
+                            getLog().info("Updated doc file: " + docFile);
+                        } else {
+                            getLog().debug("No changes to doc file: " + 
docFile);
+                        }
+                        if (isFailFast()) {
+                            throw new MojoExecutionException("Failed build due 
failFast=true");
+                        }
+                    }
+                } else {
+                    getLog().warn("No component docs found in folder: " + 
docFolder);
+                }
+            }
+        }
+    }
+
+    private List parseSpringBootAutoConfigreModels(File file) throws 
IOException, DeserializationException {
+        List<SpringBootAutoConfigureOptionModel> answer = new ArrayList<>();
+
+        JsonObject obj = (JsonObject) Jsoner.deserialize(new FileReader(file));
+
+        JsonArray arr = obj.getCollection("properties");
+        if (arr != null && !arr.isEmpty()) {
+            arr.forEach((e) -> {
+                JsonObject row = (JsonObject) e;
+                String name = row.getString("name");
+                String javaType = row.getString("type");
+                String desc = row.getString("description");
+                String defaultValue = row.getString("defaultValue");
+
+                // skip this special option
+                boolean skip = name.endsWith("customizer.enabled");
+                if (!skip) {
+                    SpringBootAutoConfigureOptionModel model = new 
SpringBootAutoConfigureOptionModel();
+                    model.setName(name);
+                    model.setJavaType(javaType);
+                    model.setDefaultValue(defaultValue);
+                    model.setDescription(desc);
+                    answer.add(model);
+                }
+            });
+        }
+
+        return answer;
+    }
+
+    private boolean updateAutoConfigureOptions(File file, String changed) 
throws MojoExecutionException {
+        if (!file.exists()) {
+            return false;
+        }
+
+        try {
+            String text = loadText(new FileInputStream(file));
+
+            String existing = StringHelper.between(text, "// 
spring-boot-auto-configure options: START", "// spring-boot-auto-configure 
options: END");
+            if (existing != null) {
+                // remove leading line breaks etc
+                existing = existing.trim();
+                changed = changed.trim();
+                if (existing.equals(changed)) {
+                    return false;
+                } else {
+                    String before = StringHelper.before(text, "// 
spring-boot-auto-configure options: START");
+                    String after = StringHelper.after(text, "// 
spring-boot-auto-configure options: END");
+                    text = before + "// spring-boot-auto-configure options: 
START\n" + changed + "\n// spring-boot-auto-configure options: END" + after;
+                    writeText(file, text);
+                    return true;
+                }
+            } else {
+                getLog().warn("Cannot find markers in file " + file);
+                getLog().warn("Add the following markers");
+                getLog().warn("\t// spring-boot-auto-configure options: 
START");
+                getLog().warn("\t// spring-boot-auto-configure options: END");
+                if (isFailFast()) {
+                    throw new MojoExecutionException("Failed build due 
failFast=true");
+                }
+                return false;
+            }
+        } catch (Exception e) {
+            throw new MojoExecutionException("Error reading file " + file + " 
Reason: " + e, e);
+        }
+    }
+
+    private String 
templateAutoConfigurationOptions(List<SpringBootAutoConfigureOptionModel> 
options) throws MojoExecutionException {
+        try {
+            String template = 
loadText(UpdateSpringBootAutoConfigurationReadmeMojo.class.getClassLoader().getResourceAsStream("spring-boot-auto-configure-options.mvel"));
+            String out = (String) TemplateRuntime.eval(template, options);
+            return out;
+        } catch (Exception e) {
+            throw new MojoExecutionException("Error processing mvel template. 
Reason: " + e, e);
+        }
+    }
+
+    private boolean isFailFast() {
+        return failFast != null && failFast;
+    }
+
+}
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/SpringBootAutoConfigureOptionModel.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/SpringBootAutoConfigureOptionModel.java
new file mode 100644
index 0000000..686896a
--- /dev/null
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/SpringBootAutoConfigureOptionModel.java
@@ -0,0 +1,112 @@
+/**
+ * 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.packaging.model;
+
+import static org.apache.camel.maven.packaging.StringHelper.wrapCamelCaseWords;
+
+public class SpringBootAutoConfigureOptionModel {
+
+    private String name;
+    private String javaType;
+    private String defaultValue;
+    private String description;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getJavaType() {
+        return javaType;
+    }
+
+    public void setJavaType(String javaType) {
+        this.javaType = javaType;
+    }
+
+    public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    public void setDefaultValue(String defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getShortJavaType() {
+        return getShortJavaType(40);
+    }
+
+    public String getShortJavaType(int watermark) {
+        if (javaType.startsWith("java.util.Map")) {
+            return "Map";
+        } else if (javaType.startsWith("java.util.Set")) {
+            return "Set";
+        } else if (javaType.startsWith("java.util.List")) {
+            return "List";
+        }
+
+        String text = javaType;
+
+        int pos = text.lastIndexOf(".");
+        if (pos != -1) {
+            text = text.substring(pos + 1);
+        }
+
+        // use non wrapped types
+        if ("Boolean".equals(text)) {
+            text = "boolean";
+        } else if ("Long".equals(text)) {
+            text = "long";
+        } else if ("Integer".equals(text)) {
+            text = "int";
+        }
+
+        return text;
+    }
+
+    public String getShortDefaultValue(int watermark) {
+        if (defaultValue == null || defaultValue.isEmpty()) {
+            return "";
+        }
+        String text = defaultValue;
+        if (text.endsWith("<T>")) {
+            text = text.substring(0, text.length() - 3);
+        } else if (text.endsWith("<T>>")) {
+            text = text.substring(0, text.length() - 4);
+        }
+
+        // TODO: dirty hack for AUTO_ACKNOWLEDGE which we should wrap
+        if ("AUTO_ACKNOWLEDGE".equals(text)) {
+            return "AUTO_ ACKNOWLEDGE";
+        }
+
+        return text;
+    }
+
+
+}
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/resources/spring-boot-auto-configure-options.mvel
 
b/tooling/maven/camel-package-maven-plugin/src/main/resources/spring-boot-auto-configure-options.mvel
new file mode 100644
index 0000000..47f07e2
--- /dev/null
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/resources/spring-boot-auto-configure-options.mvel
@@ -0,0 +1,15 @@
+=== Spring Boot Auto-Configuration
+
+@if{this.isEmpty()}
+The component has no Spring Boot auto configuration options.
+@else{}
+The component supports @{this.size()} options, which are listed below.
+@end{}
+
+@if{!this.isEmpty()}
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+@foreach{row : this}| *@{row.name}* | @{row.description} | 
@{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
+@end{}|===
+@end{}
\ No newline at end of file

Reply via email to