You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2017/02/03 19:31:44 UTC

[6/7] camel git commit: CAMEL-10774: Update readme automatic

CAMEL-10774: Update readme automatic


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

Branch: refs/heads/master
Commit: 8086210cc977f5d0b9c8a5f7d565f987ecc502de
Parents: fd457a4
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Feb 3 19:14:31 2017 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Feb 3 20:31:28 2017 +0100

----------------------------------------------------------------------
 components/readme.adoc                          | 107 ++++++++++------
 .../camel/maven/packaging/PackageHelper.java    |  18 +++
 .../maven/packaging/PrepareReadmeMojo.java      | 125 ++++++++++++++++++-
 .../maven/packaging/ReadmeComponentMojo.java    | 101 ++++++++++++++-
 .../camel/maven/packaging/model/OtherModel.java | 116 +++++++++++++++++
 .../src/main/resources/readme-others.mvel       |  10 ++
 6 files changed, 439 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/8086210c/components/readme.adoc
----------------------------------------------------------------------
diff --git a/components/readme.adoc b/components/readme.adoc
index c09147b..1644360 100644
--- a/components/readme.adoc
+++ b/components/readme.adoc
@@ -588,44 +588,79 @@ Components
 
 Other Components
 ^^^^^^^^^^^^^^^^
-[width="100%",cols="4,6",options="header"]
+
+// others: START
+[width="100%",cols="4,1,5",options="header"]
 |=======================================================================
-| Component | Description
-| BAM (camel-bam) | *deprecated* Business Activity Monitoring
-| Blueprint (camel-blueprint) | Using Camel with OSGi Blueprint
-| Core OSGi (camel-core-osgi) | Using Camel with OSGi
-| CDI (camel-cdi) | Using Camel with CDI
-| Eclipse (camel-eclipse) | Camel classpath scanning support for running in Eclipse Desktop Applications
-| Grape (camel-grape) | Using Grape to download and install Camel components into existing running Camel application
-| Guice (camel-guice) | Using Camel with Guice
-| HawtDB (camel-hawtdb) | *deprecated* Using HawtDB as persistent EIP store
-| Hystrix (camel-hystrix) | Circuit Breaker EIP using Hystrix
-| LevelDB (camel-leveldb) | Using LevelDB as persistent EIP store
-| Jasypt (camel-jasypt) | Security using Jasypt
-| Kura (camel-kura) | Using Camel with Eclipse Kura (OSGi)
-| Ribbon (camel-ribbon) | Using Netflixx Ribbon for client side load balancing
-| RX (camel-rx) | Camel Reactive using RxJava library
-| Scala (camel-scala) | Camel Scala DSL
-| SCR (camel-scr) | Camel with OSGi SCR (Declarative Services)
-| Servlet Listener (camel-servletlistener) | Bootstrapping Camel using Servet Listener
-| Shiro (camel-shiro) | Security using Shiro
-| Spring (camel-spring) | Camel Spring XML DSL
-| Spring Boot (camel-spring-boot) | Using Camel with Spring Boot
-| Spring Cloud (camel-spring-cloud) | Using Camel with Spring Cloud
-| Spring DM (camel-spring-dm) | *deprecated* Camel SpringDM (OSGi) XML DSL
-| Spring Java Config (camel-spring-javaconfig) | Using Camel with Spring Java Configuration
-| Spring Security (camel-spring-security) | Security using Spring
-| Swagger (camel-swagger) | *deprecated* Rest-dsl support for using swagger api-doc
-| Swagger Java (camel-swagger) | Rest-dsl support for using swagger api-doc
-| Test (camel-test) | Camel unit testing
-| Test Blueprint (camel-test-blueprint) | Camel unit testing with OSGi Blueprint
-| Test CDI (camel-test-cdi) | Camel unit testing with CDI
-| Test Karaf (camel-test-karaf) | Camel integration testing with Apache Karaf
-| Test Spring (camel-test-spring) | Camel unit testing with Spring
-| TestNG (camel-testng) | *deprecated* Camel unit testing with TestNG
-| UrlRewrite (camel-urlrewrite) | URL rewrite support for HTTP components
-| Zipkin (camel-zipkin) | Distributed message tracing using Zipkin
+| Component | Available From | Description
+
+| link:camel-bam/src/main/docs/bam.adoc[Bam] (camel-bam) |  | *deprecated* Camel Business Activity Monitor support
+
+| link:camel-blueprint/src/main/docs/blueprint.adoc[Blueprint] (camel-blueprint) |  | Camel OSGi Blueprint support
+
+| link:camel-cdi/src/main/docs/cdi.adoc[Cdi] (camel-cdi) |  | Camel Contexts and Dependency Injection Support
+
+| link:camel-cxf-transport/src/main/docs/cxf-transport.adoc[Cxf Transport] (camel-cxf-transport) |  | Camel Transport for CXF
+
+| link:camel-eclipse/src/main/docs/eclipse.adoc[Eclipse] (camel-eclipse) | 2.3.0 | *deprecated* Camel Eclipse support
+
+| link:camel-guice/src/main/docs/guice.adoc[Guice] (camel-guice) |  | Camel Guice
+
+| link:camel-hawtdb/src/main/docs/hawtdb.adoc[Hawtdb] (camel-hawtdb) |  | *deprecated* Camel HawtDB Support
+
+| link:camel-hystrix/src/main/docs/hystrix.adoc[Hystrix] (camel-hystrix) |  | Camel Hystrix support
+
+| link:camel-jasypt/src/main/docs/jasypt.adoc[Jasypt] (camel-jasypt) |  | Camel Jasypt support
+
+| link:camel-kura/src/main/docs/kura.adoc[Kura] (camel-kura) |  | Camel Kura support
+
+| link:camel-leveldb/src/main/docs/leveldb.adoc[Leveldb] (camel-leveldb) |  | Camel LevelDB Support
+
+| link:camel-ribbon/src/main/docs/ribbon.adoc[Ribbon] (camel-ribbon) |  | Camel Components
+
+| link:camel-ruby/src/main/docs/ruby.adoc[Ruby] (camel-ruby) |  | Camel Ruby support
+
+| link:camel-rx/src/main/docs/rx.adoc[Rx] (camel-rx) |  | Camel Reactive Extensions support
+
+| link:camel-scala/src/main/docs/scala.adoc[Scala] (camel-scala) |  | Camel Scala DSL
+
+| link:camel-scr/src/main/docs/scr.adoc[Scr] (camel-scr) |  | Camel SCR support
+
+| link:camel-servletlistener/src/main/docs/servletlistener.adoc[Servletlistener] (camel-servletlistener) |  | Camel servlet listener for bootstrapping Camel in Web Applications
+
+| link:camel-shiro/src/main/docs/shiro.adoc[Shiro] (camel-shiro) |  | Camel Shiro Security support
+
+| link:camel-spring-boot/src/main/docs/spring-boot.adoc[Spring Boot] (camel-spring-boot) |  | Camel :: Spring Boot
+
+| link:camel-spring-cloud/src/main/docs/spring-cloud.adoc[Spring Cloud] (camel-spring-cloud) |  | Camel :: Spring Cloud
+
+| link:camel-spring-dm/src/main/docs/spring-dm.adoc[Spring Dm] (camel-spring-dm) |  | *deprecated* Camel Spring DM support
+
+| link:camel-spring-javaconfig/src/main/docs/spring-javaconfig.adoc[Spring Javaconfig] (camel-spring-javaconfig) |  | Camel Spring JavaConfig support
+
+| link:camel-spring-security/src/main/docs/spring-security.adoc[Spring Security] (camel-spring-security) |  | Camel Spring Security support
+
+| link:camel-swagger/src/main/docs/swagger.adoc[Swagger] (camel-swagger) |  | *deprecated* Camel Swagger support
+
+| link:camel-swagger-java/src/main/docs/swagger-java.adoc[Swagger Java] (camel-swagger-java) |  | Camel Swagger Java support
+
+| link:camel-test/src/main/docs/test.adoc[Test] (camel-test) |  | Camel Testing Library using JUnit
+
+| link:camel-test-blueprint/src/main/docs/test-blueprint.adoc[Test Blueprint] (camel-test-blueprint) |  | Camel Testing Blueprint Library using JUnit
+
+| link:camel-test-cdi/src/main/docs/test-cdi.adoc[Test Cdi] (camel-test-cdi) |  | Camel Testing Library using JUnit and CDI
+
+| link:camel-test-karaf/src/main/docs/test-karaf.adoc[Test Karaf] (camel-test-karaf) |  | Camel Testing Library using Pax Exam, Karaf and JUnit
+
+| link:camel-test-spring/src/main/docs/test-spring.adoc[Test Spring] (camel-test-spring) |  | Camel Testing Library using JUnit and Spring 4.1+
+
+| link:camel-testng/src/main/docs/testng.adoc[Testng] (camel-testng) |  | *deprecated* Camel Testing Library using TestNG
+
+| link:camel-urlrewrite/src/main/docs/urlrewrite.adoc[Urlrewrite] (camel-urlrewrite) |  | Camel URLRewrite support
+
+| link:camel-zipkin/src/main/docs/zipkin.adoc[Zipkin] (camel-zipkin) |  | Camel Zipkin Support
 |=======================================================================
+// others: END
 
 
 

http://git-wip-us.apache.org/repos/asf/camel/blob/8086210c/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageHelper.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageHelper.java
index c84768f..5d421b9 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageHelper.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageHelper.java
@@ -150,4 +150,22 @@ public final class PackageHelper {
         }
     }
 
+    public static class CamelOthersModelFilter implements FileFilter {
+
+        @Override
+        public boolean accept(File pathname) {
+            if ("camel-core-osgi".equals(pathname)
+                || "camel-core-xml".equals(pathname)
+                || "camel-http-common".equals(pathname)
+                || "camel-jetty".equals(pathname)
+                || "camel-jetty-common".equals(pathname)
+                || "camel-linkedin".equals(pathname)
+                || "camel-olingo2".equals(pathname)
+                || "camel-salesforce".equals(pathname)) {
+                return false;
+            }
+            return pathname.isDirectory() || pathname.getName().endsWith(".json");
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/8086210c/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReadmeMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReadmeMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReadmeMojo.java
index 8617b58..e762c01 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReadmeMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReadmeMojo.java
@@ -33,6 +33,7 @@ import org.apache.camel.maven.packaging.model.ComponentModel;
 import org.apache.camel.maven.packaging.model.DataFormatModel;
 import org.apache.camel.maven.packaging.model.EipModel;
 import org.apache.camel.maven.packaging.model.LanguageModel;
+import org.apache.camel.maven.packaging.model.OtherModel;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
@@ -44,7 +45,7 @@ import static org.apache.camel.maven.packaging.PackageHelper.loadText;
 import static org.apache.camel.maven.packaging.PackageHelper.writeText;
 
 /**
- * Prepares the readme.md files content up to date with the components, data formats, and languages.
+ * Prepares the readme.md files content up to date with the components, data formats, languages, and others.
  *
  * @goal prepare-readme
  */
@@ -88,6 +89,13 @@ public class PrepareReadmeMojo extends AbstractMojo {
     protected File languagesDir;
 
     /**
+     * The directory for others catalog
+     *
+     * @parameter default-value="${project.build.directory}/classes/org/apache/camel/catalog/others"
+     */
+    protected File othersDir;
+
+    /**
      * The directory for camel-core
      *
      * @parameter default-value="${project.directory}/../../../camel-core"
@@ -124,6 +132,7 @@ public class PrepareReadmeMojo extends AbstractMojo {
         executeLanguagesReadme(true);
         // update readme file in components
         executeComponentsReadme(false);
+        executeOthersReadme();
         executeDataFormatsReadme(false);
         executeLanguagesReadme(false);
     }
@@ -244,6 +253,48 @@ public class PrepareReadmeMojo extends AbstractMojo {
         }
     }
 
+    protected void executeOthersReadme() throws MojoExecutionException, MojoFailureException {
+        Set<File> otherFiles = new TreeSet<>();
+
+        if (othersDir != null && othersDir.isDirectory()) {
+            File[] files = othersDir.listFiles();
+            if (files != null) {
+                otherFiles.addAll(Arrays.asList(files));
+            }
+        }
+
+        try {
+            List<OtherModel> others = new ArrayList<>();
+            for (File file : otherFiles) {
+                String json = loadText(new FileInputStream(file));
+                OtherModel model = generateOtherModel(json);
+                others.add(model);
+            }
+
+            // sort the models
+            Collections.sort(others, new OtherComparator());
+
+            // update the big readme file in the components dir
+            File file = new File(readmeComponentsDir, "readme.adoc");
+
+            // update regular components
+            boolean exists = file.exists();
+            String changed = templateOthers(others);
+            boolean updated = updateOthers(file, changed);
+
+            if (updated) {
+                getLog().info("Updated readme.adoc file: " + file);
+            } else if (exists) {
+                getLog().debug("No changes to readme.adoc file: " + file);
+            } else {
+                getLog().warn("No readme.adoc file: " + file);
+            }
+
+        } catch (IOException e) {
+            throw new MojoFailureException("Error due " + e.getMessage(), e);
+        }
+    }
+
     protected void executeDataFormatsReadme(boolean core) throws MojoExecutionException, MojoFailureException {
         Set<File> dataFormatFiles = new TreeSet<>();
 
@@ -388,6 +439,18 @@ public class PrepareReadmeMojo extends AbstractMojo {
         }
     }
 
+    private String templateOthers(List<OtherModel> models) throws MojoExecutionException {
+        try {
+            String template = loadText(ReadmeComponentMojo.class.getClassLoader().getResourceAsStream("readme-others.mvel"));
+            Map<String, Object> map = new HashMap<>();
+            map.put("others", models);
+            String out = (String) TemplateRuntime.eval(template, map);
+            return out;
+        } catch (Exception e) {
+            throw new MojoExecutionException("Error processing mvel template. Reason: " + e, e);
+        }
+    }
+
     private String templateDataFormats(List<DataFormatModel> models) throws MojoExecutionException {
         try {
             String template = loadText(ReadmeComponentMojo.class.getClassLoader().getResourceAsStream("readme-dataformats.mvel"));
@@ -480,6 +543,40 @@ public class PrepareReadmeMojo extends AbstractMojo {
         }
     }
 
+    private boolean updateOthers(File file, String changed) throws MojoExecutionException {
+        if (!file.exists()) {
+            return false;
+        }
+
+        try {
+            String text = loadText(new FileInputStream(file));
+
+            String existing = StringHelper.between(text, "// others: START", "// others: 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, "// others: START");
+                    String after = StringHelper.after(text, "// others: END");
+                    text = before + "// others: START\n" + changed + "\n// others: 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// others: START");
+                getLog().warn("\t// others: END");
+                return false;
+            }
+        } catch (Exception e) {
+            throw new MojoExecutionException("Error reading file " + file + " Reason: " + e, e);
+        }
+    }
+
     private boolean updateDataFormats(File file, String changed) throws MojoExecutionException {
         if (!file.exists()) {
             return false;
@@ -566,6 +663,15 @@ public class PrepareReadmeMojo extends AbstractMojo {
         }
     }
 
+    private static class OtherComparator implements Comparator<OtherModel> {
+
+        @Override
+        public int compare(OtherModel o1, OtherModel o2) {
+            // lets sort by title
+            return o1.getTitle().compareToIgnoreCase(o2.getTitle());
+        }
+    }
+
     private static class DataFormatComparator implements Comparator<DataFormatModel> {
 
         @Override
@@ -623,6 +729,23 @@ public class PrepareReadmeMojo extends AbstractMojo {
         return component;
     }
 
+    private OtherModel generateOtherModel(String json) {
+        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("other", json, false);
+
+        OtherModel other = new OtherModel();
+        other.setName(JSonSchemaHelper.getSafeValue("name", rows));
+        other.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
+        other.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
+        other.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
+        other.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
+        other.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
+        other.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
+        other.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
+        other.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+
+        return other;
+    }
+
     private DataFormatModel generateDataFormatModel(String json) {
         List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("dataformat", json, false);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/8086210c/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ReadmeComponentMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ReadmeComponentMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ReadmeComponentMojo.java
index 1c3ecca..632fdd4 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ReadmeComponentMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ReadmeComponentMojo.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.stream.Collectors;
@@ -34,6 +35,7 @@ import org.apache.camel.maven.packaging.model.DataFormatOptionModel;
 import org.apache.camel.maven.packaging.model.EndpointOptionModel;
 import org.apache.camel.maven.packaging.model.LanguageModel;
 import org.apache.camel.maven.packaging.model.LanguageOptionModel;
+import org.apache.camel.maven.packaging.model.OtherModel;
 import org.apache.maven.model.Resource;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -48,7 +50,7 @@ import static org.apache.camel.maven.packaging.PackageHelper.writeText;
 import static org.apache.camel.maven.packaging.StringHelper.isEmpty;
 
 /**
- * Generate or updates the component/dataformat/language readme.md and .adoc files in the project root directory.
+ * Generate or updates the component/dataformat/language/other readme.md and .adoc files in the project root directory.
  *
  * @goal update-readme
  */
@@ -96,6 +98,7 @@ public class ReadmeComponentMojo extends AbstractMojo {
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
         executeComponent();
+        executeOther();
         executeDataFormat();
         executeLanguage();
     }
@@ -160,6 +163,44 @@ public class ReadmeComponentMojo extends AbstractMojo {
         }
     }
 
+    private void executeOther() throws MojoExecutionException, MojoFailureException {
+        // find the other names
+        List<String> otherNames = findOtherNames();
+
+        final Set<File> jsonFiles = new TreeSet<File>();
+        PackageHelper.findJsonFiles(buildDir, jsonFiles, new PackageHelper.CamelOthersModelFilter());
+
+        // only if there is other we should update the documentation files
+        if (!otherNames.isEmpty()) {
+            getLog().debug("Found " + otherNames.size() + " others");
+            for (String otherName : otherNames) {
+                String json = loadOtherJson(jsonFiles, otherName);
+                if (json != null) {
+                    File file = new File(docDir, otherName + ".adoc");
+
+                    OtherModel model = generateOtherModel(otherName, json);
+
+                    boolean exists = file.exists();
+                    boolean updated;
+
+                    updated = updateTitles(file, model.getTitle());
+                    updated |= updateAvailableFrom(file, model.getFirstVersion());
+
+                    if (updated) {
+                        getLog().info("Updated doc file: " + file);
+                    } else if (exists) {
+                        getLog().debug("No changes to doc file: " + file);
+                    } else {
+                        getLog().warn("No other doc file: " + file);
+                        if (isFailFast()) {
+                            throw new MojoExecutionException("Failed build due failFast=true");
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     private void executeDataFormat() throws MojoExecutionException, MojoFailureException {
         // find the dataformat names
         List<String> dataFormatNames = findDataFormatNames();
@@ -603,6 +644,23 @@ public class ReadmeComponentMojo extends AbstractMojo {
         return null;
     }
 
+    private String loadOtherJson(Set<File> jsonFiles, String otherName) {
+        try {
+            for (File file : jsonFiles) {
+                if (file.getName().equals(otherName + ".json")) {
+                    String json = loadText(new FileInputStream(file));
+                    boolean isOther = json.contains("\"kind\": \"other\"");
+                    if (isOther) {
+                        return json;
+                    }
+                }
+            }
+        } catch (IOException e) {
+            // ignore
+        }
+        return null;
+    }
+
     private ComponentModel generateComponentModel(String componentName, String json) {
         List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("component", json, false);
 
@@ -757,6 +815,23 @@ public class ReadmeComponentMojo extends AbstractMojo {
         return language;
     }
 
+    private OtherModel generateOtherModel(String otherName, String json) {
+        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("other", json, false);
+
+        OtherModel other = new OtherModel();
+        other.setTitle(JSonSchemaHelper.getSafeValue("title", rows));
+        other.setName(JSonSchemaHelper.getSafeValue("name", rows));
+        other.setDescription(JSonSchemaHelper.getSafeValue("description", rows));
+        other.setFirstVersion(JSonSchemaHelper.getSafeValue("firstVersion", rows));
+        other.setLabel(JSonSchemaHelper.getSafeValue("label", rows));
+        other.setDeprecated(JSonSchemaHelper.getSafeValue("deprecated", rows));
+        other.setGroupId(JSonSchemaHelper.getSafeValue("groupId", rows));
+        other.setArtifactId(JSonSchemaHelper.getSafeValue("artifactId", rows));
+        other.setVersion(JSonSchemaHelper.getSafeValue("version", rows));
+
+        return other;
+    }
+
     private String templateComponentHeader(ComponentModel model) throws MojoExecutionException {
         try {
             String template = loadText(ReadmeComponentMojo.class.getClassLoader().getResourceAsStream("component-header.mvel"));
@@ -835,6 +910,30 @@ public class ReadmeComponentMojo extends AbstractMojo {
         return componentNames;
     }
 
+    private List<String> findOtherNames() {
+        List<String> otherNames = new ArrayList<String>();
+        for (Resource r : project.getBuild().getResources()) {
+            File f = new File(r.getDirectory());
+            if (!f.exists()) {
+                f = new File(project.getBasedir(), r.getDirectory());
+            }
+            f = new File(f, "META-INF/services/org/apache/camel/other.properties");
+
+            if (f.exists() && f.isFile()) {
+                try {
+                    Properties prop = new Properties();
+                    prop.load(new FileInputStream(f));
+
+                    String name = prop.getProperty("name");
+                    otherNames.add(name);
+                } catch (Exception e) {
+                    // ignore
+                }
+            }
+        }
+        return otherNames;
+    }
+
     private List<String> findDataFormatNames() {
         List<String> dataFormatNames = new ArrayList<String>();
         for (Resource r : project.getBuild().getResources()) {

http://git-wip-us.apache.org/repos/asf/camel/blob/8086210c/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherModel.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherModel.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherModel.java
new file mode 100644
index 0000000..fc28266
--- /dev/null
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/model/OtherModel.java
@@ -0,0 +1,116 @@
+/**
+ * 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;
+
+public class OtherModel {
+
+    private String kind;
+    private String name;
+    private String title;
+    private String description;
+    private String firstVersion;
+    private String label;
+    private String deprecated;
+    private String groupId;
+    private String artifactId;
+    private String version;
+
+    public String getKind() {
+        return kind;
+    }
+
+    public void setKind(String kind) {
+        this.kind = kind;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getFirstVersion() {
+        return firstVersion;
+    }
+
+    public void setFirstVersion(String firstVersion) {
+        this.firstVersion = firstVersion;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public String getDeprecated() {
+        return deprecated;
+    }
+
+    public void setDeprecated(String deprecated) {
+        this.deprecated = deprecated;
+    }
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(String artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getDocLink() {
+        return artifactId + "/src/main/docs";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/8086210c/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-others.mvel
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-others.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-others.mvel
new file mode 100644
index 0000000..1841149
--- /dev/null
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-others.mvel
@@ -0,0 +1,10 @@
+@if{!others.isEmpty()}
+
+[width="100%",cols="4,1,5",options="header"]
+|=======================================================================
+| Component | Available From | Description
+@foreach{row : others}
+| link:@{row.docLink}/${row.name}.adoc[@{row.title}] (@{row.artifactId}) | @{row.firstVersion} | @if{row.deprecated == "true"}*deprecated* @end{}@{row.description}
+@end{}|=======================================================================
+
+@end{}
\ No newline at end of file