CAMEL-8025: Added karaf commands to show component list.

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

Branch: refs/heads/master
Commit: 7374b1da11d051a1e5c72c3766e6396109e8eb2c
Parents: 6c37f22
Author: Claus Ibsen <davscl...@apache.org>
Authored: Mon Nov 10 13:18:17 2014 +0100
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Mon Nov 10 14:51:12 2014 +0100

----------------------------------------------------------------------
 .../management/mbean/ManagedCamelContext.java   |   5 +-
 .../camel/component/event/EventComponent.java   |   7 +-
 .../camel/component/event/EventEndpoint.java    |   5 +-
 .../karaf/commands/CamelCommandSupport.java     |   8 +
 .../camel/karaf/commands/CamelController.java   |  10 +
 .../camel/karaf/commands/ComponentList.java     | 190 +++++++++++++++++++
 .../commands/internal/CamelControllerImpl.java  |  70 +++++++
 .../OSGI-INF/blueprint/camel-commands.xml       |   9 +
 .../tools/apt/EndpointAnnotationProcessor.java  |  36 +++-
 9 files changed, 325 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
 
b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
index b9f0023..2cd0aa4 100644
--- 
a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
+++ 
b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
@@ -495,10 +495,11 @@ public class ManagedCamelContext extends 
ManagedPerformanceCounter implements Ti
                 String name = entry.getKey();
                 String description = null;
                 // the status can be:
-                // - loaded = in use
+                // - in use = used by Camel
                 // - classpath = on the classpath
                 // - release = available from the Apache Camel release
-                String status = context.hasComponent(name) != null ? "loaded" 
: "classpath";
+                // TODO: gather list of components in the Camel release
+                String status = context.hasComponent(name) != null ? "in use" 
: "on classpath";
                 String type = null;
                 String groupId = null;
                 String artifactId = null;

http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java
----------------------------------------------------------------------
diff --git 
a/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java
 
b/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java
index 9296f64..acb49fb 100644
--- 
a/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java
+++ 
b/components/camel-spring/src/main/java/org/apache/camel/component/event/EventComponent.java
@@ -21,6 +21,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.impl.UriEndpointComponent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeansException;
@@ -31,19 +32,21 @@ import 
org.springframework.context.ConfigurableApplicationContext;
 
 /**
  * An <a href="http://camel.apache.org/event.html";>Event Component</a>
- * for working with Spring ApplicationEvents
+ * for working with Spring ApplicationEvents.
  * 
  * @version 
  */
-public class EventComponent extends DefaultComponent implements 
ApplicationContextAware {
+public class EventComponent extends UriEndpointComponent implements 
ApplicationContextAware {
     private static final Logger LOG = 
LoggerFactory.getLogger(EventComponent.class);
     private ApplicationContext applicationContext;
     private final Set<EventEndpoint> endpoints = new 
LinkedHashSet<EventEndpoint>();
 
     public EventComponent() {
+        super(EventEndpoint.class);
     }
 
     public EventComponent(ApplicationContext applicationContext) {
+        super(EventEndpoint.class);
         setApplicationContext(applicationContext);
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java
----------------------------------------------------------------------
diff --git 
a/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java
 
b/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java
index fceea03..483bd5f 100644
--- 
a/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java
+++ 
b/components/camel-spring/src/main/java/org/apache/camel/component/event/EventEndpoint.java
@@ -23,6 +23,7 @@ import org.apache.camel.impl.DefaultEndpoint;
 import org.apache.camel.impl.DefaultProducer;
 import org.apache.camel.processor.loadbalancer.LoadBalancer;
 import org.apache.camel.processor.loadbalancer.TopicLoadBalancer;
+import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.util.ObjectHelper;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
@@ -31,13 +32,13 @@ import org.springframework.context.ApplicationEvent;
 
 import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException;
 
-
 /**
  * An <a href="http://camel.apache.org/event.html";>Event Endpoint</a>
  * for working with Spring ApplicationEvents
  *
  * @version 
  */
+@UriEndpoint(scheme = "spring-event", consumerClass = EventConsumer.class)
 public class EventEndpoint extends DefaultEndpoint implements 
ApplicationContextAware {
     private LoadBalancer loadBalancer;
     private ApplicationContext applicationContext;
@@ -50,7 +51,7 @@ public class EventEndpoint extends DefaultEndpoint implements 
ApplicationContext
     /**
      * <b>Note:</b> It is preferred to create endpoints using the associated
      * component.
-     * @param endpointUri
+     * @deprecated
      */
     @Deprecated
     public EventEndpoint(String endpointUri) {

http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java
----------------------------------------------------------------------
diff --git 
a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java
 
b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java
index a1edfe2..6076af2 100644
--- 
a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java
+++ 
b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelCommandSupport.java
@@ -29,4 +29,12 @@ public abstract class CamelCommandSupport extends 
OsgiCommandSupport {
         this.camelController = camelController;
     }
 
+    String safeNull(String s) {
+        if (s == null) {
+            return "";
+        } else {
+            return s;
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java
----------------------------------------------------------------------
diff --git 
a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java
 
b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java
index aa5bdf8..2495a0c 100644
--- 
a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java
+++ 
b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CamelController.java
@@ -112,7 +112,17 @@ public interface CamelController {
      * @param uri              the endpoint uri
      * @param allOptions       whether to explain all options, or only the 
explicit configured options from the uri
      * @return a JSON schema with explanation of the options
+     * @throws java.lang.Exception is thrown if error loading resources to 
explain the endpoint
      */
     String explainEndpoint(String camelContextName, String uri, boolean 
allOptions) throws Exception;
 
+    /**
+     * Lists all components and include information
+     *
+     * @param camelContextName the Camel context.
+     * @return a list of key/value pairs with component information
+     * @throws java.lang.Exception is thrown if error loading resources to 
gather component information
+     */
+    List<Map<String, String>> listComponents(String camelContextName) throws 
Exception;
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ComponentList.java
----------------------------------------------------------------------
diff --git 
a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ComponentList.java
 
b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ComponentList.java
new file mode 100644
index 0000000..1c196a3
--- /dev/null
+++ 
b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/ComponentList.java
@@ -0,0 +1,190 @@
+/**
+ * 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.karaf.commands;
+
+import java.io.PrintStream;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Option;
+
+/**
+ * List the Camel components available in the Karaf instance.
+ */
+@Command(scope = "camel", name = "component-list", description = "Lists all 
Camel components available in CamelContexts.")
+public class ComponentList extends CamelCommandSupport {
+
+    private static final String NAME_COLUMN_LABEL = "Name";
+    private static final String STATUS_COLUMN_LABEL = "Status";
+    private static final String MAVEN_COLUMN_LABEL = "Maven Coordinate";
+    private static final String DESCRIPTION_COLUMN_LABEL = "Description";
+
+    private static final int DEFAULT_COLUMN_WIDTH_INCREMENT = 0;
+    private static final String DEFAULT_FIELD_PREAMBLE = " ";
+    private static final String DEFAULT_FIELD_POSTAMBLE = " ";
+    private static final String DEFAULT_HEADER_PREAMBLE = " ";
+    private static final String DEFAULT_HEADER_POSTAMBLE = " ";
+    private static final int DEFAULT_FORMAT_BUFFER_LENGTH = 24;
+    // descriptions can be very long so clip by default after 120 chars
+    private static final int MAX_COLUMN_WIDTH = 120;
+    private static final int MIN_COLUMN_WIDTH = 12;
+
+    @Argument(index = 0, name = "name", description = "The Camel context name 
where to look for the components", required = true, multiValued = false)
+    String name;
+
+    @Option(name = "--verbose", aliases = "-v", description = "Verbose output 
which shows more information",
+            required = false, multiValued = false, valueToShowInHelp = "false")
+    boolean verbose = false;
+
+    protected Object doExecute() throws Exception {
+        List<Map<String, String>> components = 
camelController.listComponents(name);
+
+        if (components == null || components.isEmpty()) {
+            return null;
+        }
+
+        final Map<String, Integer> columnWidths = 
computeColumnWidths(components);
+        final String headerFormat = buildFormatString(columnWidths, true, 
verbose);
+        final String rowFormat = buildFormatString(columnWidths, false, 
verbose);
+        final PrintStream out = System.out;
+
+        if (verbose) {
+            out.println(String.format(headerFormat, NAME_COLUMN_LABEL, 
STATUS_COLUMN_LABEL, MAVEN_COLUMN_LABEL, DESCRIPTION_COLUMN_LABEL));
+            out.println(String.format(headerFormat, "----", "------", 
"----------------", "-----------"));
+        } else {
+            out.println(String.format(headerFormat, NAME_COLUMN_LABEL, 
DESCRIPTION_COLUMN_LABEL));
+            out.println(String.format(headerFormat, "----", "-----------"));
+        }
+        for (final Map<String, String> component : components) {
+            if (verbose) {
+                String name = safeNull(component.get("name"));
+                String status = safeNull(component.get("status"));
+                String maven = "";
+                if (component.containsKey("groupId") && 
component.containsKey("artifactId") && component.containsKey("version")) {
+                    maven = component.get("groupId") + "/" + 
component.get("artifactId") + "/" + component.get("version");
+                }
+                String description = safeNull(component.get("description"));
+                out.println(String.format(rowFormat, name, status, maven, 
description));
+            } else {
+                String name = safeNull(component.get("name"));
+                String description = safeNull(component.get("description"));
+                out.println(String.format(rowFormat, name, description));
+            }
+        }
+
+        return null;
+    }
+
+    private Map<String, Integer> computeColumnWidths(final 
Iterable<Map<String, String>> components) throws Exception {
+        if (components == null) {
+            return null;
+        } else {
+            // some of the options is optional so we need to start from 1
+            int maxNameLen = 1;
+            int maxStatusLen = 1;
+            int maxMavenLen = 1;
+            int maxDescriptionLen = 1;
+
+            for (final Map<String, String> component : components) {
+
+                // grab the information and compute max len
+                String name = component.get("name");
+                if (name != null) {
+                    maxNameLen = Math.max(maxNameLen, name.length());
+                }
+                String status = component.get("status");
+                if (status != null) {
+                    maxStatusLen = Math.max(maxStatusLen, status.length());
+                }
+                String type = component.get("type");
+                if (component.containsKey("groupId") && 
component.containsKey("artifactId") && component.containsKey("version")) {
+                    String mvn = component.get("groupId") + "/" + 
component.get("artifactId") + "/" + component.get("version");
+                    maxMavenLen = Math.max(maxMavenLen, mvn.length());
+                }
+                String description = component.get("description");
+                if (description != null) {
+                    maxDescriptionLen = Math.max(maxDescriptionLen, 
description.length());
+                }
+            }
+
+            final Map<String, Integer> retval = new Hashtable<String, 
Integer>(4);
+            retval.put(NAME_COLUMN_LABEL, maxNameLen);
+            retval.put(STATUS_COLUMN_LABEL, maxStatusLen);
+            retval.put(MAVEN_COLUMN_LABEL, maxMavenLen);
+            retval.put(DESCRIPTION_COLUMN_LABEL, maxDescriptionLen);
+
+            return retval;
+        }
+    }
+
+    private String buildFormatString(Map<String, Integer> columnWidths, 
boolean isHeader, boolean isVerbose) {
+        final String fieldPreamble;
+        final String fieldPostamble;
+        final int columnWidthIncrement;
+
+        if (isHeader) {
+            fieldPreamble = DEFAULT_HEADER_PREAMBLE;
+            fieldPostamble = DEFAULT_HEADER_POSTAMBLE;
+        } else {
+            fieldPreamble = DEFAULT_FIELD_PREAMBLE;
+            fieldPostamble = DEFAULT_FIELD_POSTAMBLE;
+        }
+        columnWidthIncrement = DEFAULT_COLUMN_WIDTH_INCREMENT;
+
+        if (verbose) {
+            int nameLen = Math.min(columnWidths.get(NAME_COLUMN_LABEL) + 
columnWidthIncrement, getMaxColumnWidth());
+            int statusLen = Math.min(columnWidths.get(STATUS_COLUMN_LABEL) + 
columnWidthIncrement, getMaxColumnWidth());
+            int mavenLen = Math.min(columnWidths.get(MAVEN_COLUMN_LABEL) + 
columnWidthIncrement, getMaxColumnWidth());
+            int descriptionLen = 
Math.min(columnWidths.get(DESCRIPTION_COLUMN_LABEL) + columnWidthIncrement, 
getMaxColumnWidth());
+
+            nameLen = Math.max(MIN_COLUMN_WIDTH, nameLen);
+            statusLen = Math.max(MIN_COLUMN_WIDTH, statusLen);
+            mavenLen = Math.max(MIN_COLUMN_WIDTH, mavenLen);
+            // last row does not have min width
+
+            final StringBuilder retval = new 
StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH);
+            
retval.append(fieldPreamble).append("%-").append(nameLen).append('.').append(nameLen).append('s').append(fieldPostamble).append('
 ');
+            
retval.append(fieldPreamble).append("%-").append(statusLen).append('.').append(statusLen).append('s').append(fieldPostamble).append('
 ');
+            
retval.append(fieldPreamble).append("%-").append(mavenLen).append('.').append(mavenLen).append('s').append(fieldPostamble).append('
 ');
+            
retval.append(fieldPreamble).append("%-").append(descriptionLen).append('.').append(descriptionLen).append('s').append(fieldPostamble).append('
 ');
+            return retval.toString();
+        } else {
+            int nameLen = Math.min(columnWidths.get(NAME_COLUMN_LABEL) + 
columnWidthIncrement, getMaxColumnWidth());
+            int descriptionLen = 
Math.min(columnWidths.get(DESCRIPTION_COLUMN_LABEL) + columnWidthIncrement, 
getMaxColumnWidth());
+
+            nameLen = Math.max(MIN_COLUMN_WIDTH, nameLen);
+            // last row does not have min width
+
+            final StringBuilder retval = new 
StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH);
+            
retval.append(fieldPreamble).append("%-").append(nameLen).append('.').append(nameLen).append('s').append(fieldPostamble).append('
 ');
+            
retval.append(fieldPreamble).append("%-").append(descriptionLen).append('.').append(descriptionLen).append('s').append(fieldPostamble).append('
 ');
+            return retval.toString();
+        }
+    }
+
+    private int getMaxColumnWidth() {
+        if (verbose) {
+            return Integer.MAX_VALUE;
+        } else {
+            return MAX_COLUMN_WIDTH;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java
----------------------------------------------------------------------
diff --git 
a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java
 
b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java
index 07bfcbb..0c8231a 100644
--- 
a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java
+++ 
b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/internal/CamelControllerImpl.java
@@ -19,9 +19,11 @@ package org.apache.camel.karaf.commands.internal;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
@@ -30,6 +32,7 @@ import org.apache.camel.karaf.commands.CamelController;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.spi.RestRegistry;
+import org.apache.camel.util.JsonSchemaHelper;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
@@ -232,4 +235,71 @@ public class CamelControllerImpl implements 
CamelController {
         }
         return context.explainEndpointJson(uri, allOptions);
     }
+
+    public List<Map<String, String>> listComponents(String camelContextName) 
throws Exception {
+        CamelContext context = this.getCamelContext(camelContextName);
+        if (context == null) {
+            return null;
+        }
+
+        List<Map<String, String>> answer = new ArrayList<Map<String, 
String>>();
+
+        // find all components
+        Map<String, Properties> components = context.findComponents();
+
+        // gather component detail for each component
+        for (Map.Entry<String, Properties> entry : components.entrySet()) {
+            String name = entry.getKey();
+            String description = null;
+            // the status can be:
+            // - loaded = in use
+            // - classpath = on the classpath
+            // - release = available from the Apache Camel release
+            String status = context.hasComponent(name) != null ? "in use" : 
"on classpath";
+            String type = null;
+            String groupId = null;
+            String artifactId = null;
+            String version = null;
+
+            // load component json data, and parse it to gather the component 
meta-data
+            String json = context.getComponentParameterJsonSchema(name);
+            List<Map<String, String>> rows = 
JsonSchemaHelper.parseJsonSchema("component", json, false);
+            for (Map<String, String> row : rows) {
+                if (row.containsKey("description")) {
+                    description = row.get("description");
+                } else if (row.containsKey("javaType")) {
+                    type = row.get("javaType");
+                } else if (row.containsKey("groupId")) {
+                    groupId = row.get("groupId");
+                } else if (row.containsKey("artifactId")) {
+                    artifactId = row.get("artifactId");
+                } else if (row.containsKey("version")) {
+                    version = row.get("version");
+                }
+            }
+
+            Map<String, String> row = new HashMap<>();
+            row.put("name", name);
+            row.put("status", status);
+            if (description != null) {
+                row.put("description", description);
+            }
+            if (type != null) {
+                row.put("type", type);
+            }
+            if (groupId != null) {
+                row.put("groupId", groupId);
+            }
+            if (artifactId != null) {
+                row.put("artifactId", artifactId);
+            }
+            if (version != null) {
+                row.put("version", version);
+            }
+
+            answer.add(row);
+        }
+
+        return answer;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml
----------------------------------------------------------------------
diff --git 
a/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml
 
b/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml
index 11e3fc4..d3a38f0 100644
--- 
a/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml
+++ 
b/platforms/karaf/commands/src/main/resources/OSGI-INF/blueprint/camel-commands.xml
@@ -221,6 +221,15 @@
         <null/>
       </completers>
     </command>
+    <command name="camel/component-list">
+      <action class="org.apache.camel.karaf.commands.ComponentList">
+        <property name="camelController" ref="camelController"/>
+      </action>
+      <completers>
+        <ref component-id="camelContextCompleter"/>
+        <null/>
+      </completers>
+    </command>
   </command-bundle>
 
   <bean id="camelContextCompleter" 
class="org.apache.camel.karaf.commands.completers.CamelContextCompleter">

http://git-wip-us.apache.org/repos/asf/camel/blob/7374b1da/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
----------------------------------------------------------------------
diff --git 
a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
 
b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
index 675b5fe..0c2ffe8 100644
--- 
a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
+++ 
b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
@@ -155,10 +155,8 @@ public class EndpointAnnotationProcessor extends 
AbstractProcessor {
 
         Set<EndpointOption> endpointOptions = new LinkedHashSet<>();
         findClassProperties(roundEnv, endpointOptions, classElement, "");
-        if (!endpointOptions.isEmpty()) {
-            String json = createParameterJsonSchema(componentModel, 
endpointOptions);
-            writer.println(json);
-        }
+        String json = createParameterJsonSchema(componentModel, 
endpointOptions);
+        writer.println(json);
     }
 
     public String createParameterJsonSchema(ComponentModel componentModel, 
Set<EndpointOption> options) {
@@ -166,7 +164,7 @@ public class EndpointAnnotationProcessor extends 
AbstractProcessor {
         // component model
         buffer.append("\n \"component\": {");
         buffer.append("\n    \"scheme\": \"" + componentModel.getScheme() + 
"\",");
-        buffer.append("\n    \"description\": \"" + 
sanitizeDescription(componentModel.getDescription()) + "\",");
+        buffer.append("\n    \"description\": \"" + 
componentModel.getDescription() + "\",");
         buffer.append("\n    \"javaType\": \"" + componentModel.getJavaType() 
+ "\",");
         buffer.append("\n    \"groupId\": \"" + componentModel.getGroupId() + 
"\",");
         buffer.append("\n    \"artifactId\": \"" + 
componentModel.getArtifactId() + "\",");
@@ -241,10 +239,28 @@ public class EndpointAnnotationProcessor extends 
AbstractProcessor {
         if (data != null) {
             Map<String, String> map = parseAsMap(data);
             // now we have a lot more data, so we need to load it as key/value
-            model.setDescription(map.get("projectDescription"));
-            model.setGroupId(map.get("groupId"));
-            model.setArtifactId(map.get("artifactId"));
-            model.setVersionId(map.get("version"));
+            // need to sanitize the description first
+            String doc = map.get("projectDescription");
+            if (doc != null) {
+                model.setDescription(sanitizeDescription(doc));
+            } else {
+                model.setDescription("");
+            }
+            if (map.containsKey("groupId")) {
+                model.setGroupId(map.get("groupId"));
+            } else {
+                model.setGroupId("");
+            }
+            if (map.containsKey("artifactId")) {
+                model.setArtifactId(map.get("artifactId"));
+            } else {
+                model.setArtifactId("");
+            }
+            if (map.containsKey("version")) {
+                model.setVersionId(map.get("version"));
+            } else {
+                model.setVersionId("");
+            }
         }
 
         // favor to use class javadoc of component as description
@@ -254,6 +270,8 @@ public class EndpointAnnotationProcessor extends 
AbstractProcessor {
             if (typeElement != null) {
                 String doc = elementUtils.getDocComment(typeElement);
                 if (doc != null) {
+                    // need to sanitize the description first
+                    doc = sanitizeDescription(doc);
                     // grab the first sentence only as this is for short 
description
                     int idx = doc.indexOf('.');
                     if (idx != -1) {

Reply via email to