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 2019/12/23 09:53:08 UTC

[camel] 02/03: CAMEL-14311: Add validate configuration properties to camel-catalog.

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 30117b058e84b9f2835b5be1092eda10ef297309
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Dec 23 05:01:11 2019 +0100

    CAMEL-14311: Add validate configuration properties to camel-catalog.
---
 .../camel/catalog/maven/MavenVersionManager.java   |   3 +
 .../catalog/CamelCatalogJSonSchemaResolver.java    |  17 ++-
 .../src/main/docs/camel-report-maven-plugin.adoc   |   3 +
 .../java/org/apache/camel/maven/ValidateMojo.java  | 147 +++++++++++++++++++--
 .../ConfigurationPropertiesValidationResult.java   |  58 ++++++--
 .../camel/runtimecatalog/JSonSchemaResolver.java   |   5 +
 .../camel/runtimecatalog/RuntimeCamelCatalog.java  |   5 +-
 .../runtimecatalog/impl/AbstractCamelCatalog.java  |  12 +-
 .../impl/CamelContextJSonSchemaResolver.java       |  22 ++-
 .../org/apache/camel/support/JSonSchemaHelper.java |  12 ++
 docs/components/modules/ROOT/nav.adoc              |   2 -
 .../modules/ROOT/pages/any23-dataformat.adoc       |   2 +-
 .../ROOT/pages/aws-translate-component.adoc        |   6 +-
 13 files changed, 255 insertions(+), 39 deletions(-)

diff --git a/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/MavenVersionManager.java b/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/MavenVersionManager.java
index ca4a15d..77df15e 100644
--- a/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/MavenVersionManager.java
+++ b/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/MavenVersionManager.java
@@ -163,6 +163,9 @@ public class MavenVersionManager implements VersionManager, Closeable {
         if (is == null) {
             is = MavenVersionManager.class.getClassLoader().getResourceAsStream(name);
         }
+        if (is == null) {
+            is = classLoader.getResourceAsStream(name);
+        }
 
         return is;
     }
diff --git a/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CamelCatalogJSonSchemaResolver.java b/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CamelCatalogJSonSchemaResolver.java
index a43c4e2..53b5158 100644
--- a/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CamelCatalogJSonSchemaResolver.java
+++ b/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CamelCatalogJSonSchemaResolver.java
@@ -28,6 +28,7 @@ public class CamelCatalogJSonSchemaResolver implements JSonSchemaResolver {
     private static final String MODEL_DIR = "org/apache/camel/catalog/models";
 
     private final CamelCatalog camelCatalog;
+    private ClassLoader classLoader;
 
     // 3rd party components/data-formats
     private final Map<String, String> extraComponents;
@@ -46,6 +47,11 @@ public class CamelCatalogJSonSchemaResolver implements JSonSchemaResolver {
     }
 
     @Override
+    public void setClassLoader(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
+    @Override
     public String getComponentJSonSchema(String name) {
         final String file = camelCatalog.getRuntimeProvider().getComponentJSonSchemaDirectory() + "/" + name + ".json";
 
@@ -106,7 +112,7 @@ public class CamelCatalogJSonSchemaResolver implements JSonSchemaResolver {
 
     @Override
     public String getMainJsonSchema() {
-        final String file = "META-INF/camel-main-configuration-metadata.json";
+        final String file = "org/apache/camel/catalog/main/camel-main-configuration-metadata.json";
 
         return loadResourceFromVersionManager(file);
     }
@@ -138,6 +144,15 @@ public class CamelCatalogJSonSchemaResolver implements JSonSchemaResolver {
         } catch (IOException e) {
             // ignore
         }
+        if (classLoader != null) {
+            try (InputStream is = classLoader.getResourceAsStream(file)) {
+                if (is != null) {
+                    return CatalogHelper.loadText(is);
+                }
+            } catch (IOException e) {
+                // ignore
+            }
+        }
 
         return null;
     }
diff --git a/catalog/camel-report-maven-plugin/src/main/docs/camel-report-maven-plugin.adoc b/catalog/camel-report-maven-plugin/src/main/docs/camel-report-maven-plugin.adoc
index 903b6ab..8f01ef9 100644
--- a/catalog/camel-report-maven-plugin/src/main/docs/camel-report-maven-plugin.adoc
+++ b/catalog/camel-report-maven-plugin/src/main/docs/camel-report-maven-plugin.adoc
@@ -12,6 +12,8 @@ For validating the source code for mis configured Camel:
 - endpoint uris
 - simple expressions or predicates
 - duplicate route ids
+- seda/direct endpoint pairs
+- configuration in properties files
 
 Then you can run the validate goal from the command line or from within your Java editor such as IDEA or Eclipse.
 
@@ -145,6 +147,7 @@ The maven plugin *validate* goal supports the following options which can be con
 | ignoreDeprecated | true |Whether to ignore deprecated options being used in the endpoint uri.
 | duplicateRouteId | true |Whether to validate for duplicate route ids. Route ids should be unique and if there are duplicates then Camel will fail to startup.
 | directOrSedaPairCheck | true |Whether to validate direct/seda endpoints sending to non existing consumers.
+| configurationFiles | application.properties | Location of configuration files to validate. The default is application.properties. Multiple values can be separated by comma and use wildcard pattern matching.
 | showAll | false | Whether to show all endpoints and simple expressions (both invalid and valid).
 |===
 
diff --git a/catalog/camel-report-maven-plugin/src/main/java/org/apache/camel/maven/ValidateMojo.java b/catalog/camel-report-maven-plugin/src/main/java/org/apache/camel/maven/ValidateMojo.java
index ea10bd2..ca9c324 100644
--- a/catalog/camel-report-maven-plugin/src/main/java/org/apache/camel/maven/ValidateMojo.java
+++ b/catalog/camel-report-maven-plugin/src/main/java/org/apache/camel/maven/ValidateMojo.java
@@ -18,7 +18,9 @@ package org.apache.camel.maven;
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileReader;
 import java.io.InputStream;
+import java.io.LineNumberReader;
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -26,8 +28,8 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.stream.Collectors;
 
-import org.apache.camel.PropertyBindingException;
 import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.ConfigurationPropertiesValidationResult;
 import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.catalog.EndpointValidationResult;
 import org.apache.camel.catalog.LanguageValidationResult;
@@ -165,7 +167,7 @@ public class ValidateMojo extends AbstractExecMojo {
 
     /**
      * Location of configuration files to validate. The default is application.properties
-     * Multiple values can be separated by comma and use ANT path style.
+     * Multiple values can be separated by comma and use wildcard pattern matching.
      */
     @Parameter(property = "camel.configurationFiles")
     private String configurationFiles = "application.properties";
@@ -180,6 +182,8 @@ public class ValidateMojo extends AbstractExecMojo {
         catalog.setSuggestionStrategy(new LuceneSuggestionStrategy());
         // enable loading other catalog versions dynamically
         catalog.setVersionManager(new MavenVersionManager());
+        // use custom class loading
+        catalog.getJSonSchemaResolver().setClassLoader(ValidateMojo.class.getClassLoader());
         // enable caching
         catalog.enableCache();
 
@@ -211,22 +215,25 @@ public class ValidateMojo extends AbstractExecMojo {
         doExecuteConfigurationFiles(catalog);
     }
 
-    protected void doExecuteConfigurationFiles(CamelCatalog catalog) {
+    protected void doExecuteConfigurationFiles(CamelCatalog catalog) throws MojoExecutionException {
         // TODO: implement me
 
         Set<File> propertiesFiles = new LinkedHashSet<>();
         List list = project.getResources();
         for (Object obj : list) {
-            String dir = (String) obj;
-            findPropertiesFiles(new File(dir), propertiesFiles);
+            Resource dir = (Resource) obj;
+            findPropertiesFiles(new File(dir.getDirectory()), propertiesFiles);
         }
         if (includeTest) {
             list = project.getTestResources();
             for (Object obj : list) {
-                String dir = (String) obj;
-                findPropertiesFiles(new File(dir), propertiesFiles);
+                Resource dir = (Resource) obj;
+                findPropertiesFiles(new File(dir.getDirectory()), propertiesFiles);
             }
         }
+
+        List<ConfigurationPropertiesValidationResult> results = new ArrayList<>();
+
         for (File file : propertiesFiles) {
             if (matchPropertiesFile(file)) {
                 InputStream is = null;
@@ -235,7 +242,25 @@ public class ValidateMojo extends AbstractExecMojo {
                     Properties prop = new OrderedProperties();
                     prop.load(is);
 
-                    EndpointValidationResult result = catalog.validateConfigurationProperty(line);
+                    // validate each line
+                    for (String name : prop.stringPropertyNames()) {
+                        String value = prop.getProperty(name);
+                        if (value != null) {
+                            String text = name + "=" + value;
+                            ConfigurationPropertiesValidationResult result = catalog.validateConfigurationProperty(text);
+                            // only include lines that camel can accept (as there may be non camel properties too)
+                            if (result.isAccepted()) {
+                                // try to find line number
+                                int lineNumber = findLineNumberInPropertiesFile(file, name);
+                                if (lineNumber != -1) {
+                                    result.setLineNumber(lineNumber);
+                                }
+                                results.add(result);
+                                result.setText(text);
+                                result.setFileName(file.getName());
+                            }
+                        }
+                    }
                 } catch (Exception e) {
                     getLog().warn("Error parsing file " + file + " code due " + e.getMessage(), e);
                 } finally {
@@ -243,6 +268,108 @@ public class ValidateMojo extends AbstractExecMojo {
                 }
             }
         }
+
+        int configurationErrors = 0;
+        int unknownComponents = 0;
+        int incapableErrors = 0;
+        int deprecatedOptions = 0;
+        for (ConfigurationPropertiesValidationResult result : results) {
+            int deprecated = result.getDeprecated() != null ? result.getDeprecated().size() : 0;
+            deprecatedOptions += deprecated;
+
+            boolean ok = result.isSuccess() && !result.hasWarnings();
+            if (!ok && ignoreUnknownComponent && result.getUnknownComponent() != null) {
+                // if we failed due unknown component then be okay if we should ignore that
+                unknownComponents++;
+                ok = true;
+            }
+            if (!ok && ignoreIncapable && result.getIncapable() != null) {
+                // if we failed due incapable then be okay if we should ignore that
+                incapableErrors++;
+                ok = true;
+            }
+            if (ok && !ignoreDeprecated && deprecated > 0) {
+                ok = false;
+            }
+
+            if (!ok) {
+                if (result.getUnknownComponent() != null) {
+                    unknownComponents++;
+                } else if (result.getIncapable() != null) {
+                    incapableErrors++;
+                } else {
+                    configurationErrors++;
+                }
+
+                StringBuilder sb = new StringBuilder();
+                sb.append("Configuration validation error at: ");
+                sb.append("(").append(result.getFileName());
+                if (result.getLineNumber() > 0) {
+                    sb.append(":").append(result.getLineNumber());
+                }
+                sb.append(")");
+                sb.append("\n\n");
+                String out = result.summaryErrorMessage(false, ignoreDeprecated, true);
+                sb.append(out);
+                sb.append("\n\n");
+
+                getLog().warn(sb.toString());
+            } else if (showAll) {
+                StringBuilder sb = new StringBuilder();
+                sb.append("Configuration validation passed at: ");
+                sb.append(result.getFileName());
+                if (result.getLineNumber() > 0) {
+                    sb.append(":").append(result.getLineNumber());
+                }
+                sb.append("\n");
+                sb.append("\n\t").append(result.getText());
+                sb.append("\n\n");
+
+                getLog().info(sb.toString());
+            }
+        }
+        String configurationSummary;
+        if (configurationErrors == 0) {
+            int ok = results.size() - configurationErrors - incapableErrors - unknownComponents;
+            configurationSummary = String.format("Configuration validation success: (%s = passed, %s = invalid, %s = incapable, %s = unknown components, %s = deprecated options)",
+                    ok, configurationErrors, incapableErrors, unknownComponents, deprecatedOptions);
+        } else {
+            int ok = results.size() - configurationErrors - incapableErrors - unknownComponents;
+            configurationSummary = String.format("Configuration validation error: (%s = passed, %s = invalid, %s = incapable, %s = unknown components, %s = deprecated options)",
+                    ok, configurationErrors, incapableErrors, unknownComponents, deprecatedOptions);
+        }
+        if (configurationErrors > 0) {
+            getLog().warn(configurationSummary);
+        } else {
+            getLog().info(configurationSummary);
+        }
+
+        if (failOnError && (configurationErrors > 0)) {
+            throw new MojoExecutionException(configurationSummary + "\n");
+        }
+    }
+
+    private int findLineNumberInPropertiesFile(File file, String name) {
+        name = name.trim();
+        // try to find the line number
+        try (LineNumberReader r = new LineNumberReader(new FileReader(file))) {
+            String line = r.readLine();
+            while (line != null) {
+                int pos = line.indexOf('=');
+                if (pos > 0) {
+                    line = line.substring(0, pos);
+                }
+                line = line.trim();
+                if (line.equals(name)) {
+                    return r.getLineNumber();
+                }
+                line = r.readLine();
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+
+        return -1;
     }
 
     protected void doExecuteRoutes(CamelCatalog catalog) throws MojoExecutionException, MojoFailureException {
@@ -491,7 +618,7 @@ public class ValidateMojo extends AbstractExecMojo {
             long sedaDirectEndpoints = countEndpointPairs(endpoints, "direct") + countEndpointPairs(endpoints, "seda");
             sedaDirectErrors += validateEndpointPairs(endpoints, "direct") + validateEndpointPairs(endpoints, "seda");
             if (sedaDirectErrors == 0) {
-                sedaDirectSummary = String.format("Endpoint pair (seda/direct) validation success (%s = pairs)", sedaDirectEndpoints);
+                sedaDirectSummary = String.format("Endpoint pair (seda/direct) validation success: (%s = pairs)", sedaDirectEndpoints);
             } else {
                 sedaDirectSummary = String.format("Endpoint pair (seda/direct) validation error: (%s = pairs, %s = non-pairs)", sedaDirectEndpoints, sedaDirectErrors);
             }
@@ -507,7 +634,7 @@ public class ValidateMojo extends AbstractExecMojo {
         String routeIdSummary = "";
         if (duplicateRouteId) {
             if (duplicateRouteIdErrors == 0) {
-                routeIdSummary = String.format("Duplicate route id validation success (%s = ids)", routeIds.size());
+                routeIdSummary = String.format("Duplicate route id validation success: (%s = ids)", routeIds.size());
             } else {
                 routeIdSummary = String.format("Duplicate route id validation error: (%s = ids, %s = duplicates)", routeIds.size(), duplicateRouteIdErrors);
             }
diff --git a/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/ConfigurationPropertiesValidationResult.java b/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/ConfigurationPropertiesValidationResult.java
index 8138445..9a02fcd 100644
--- a/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/ConfigurationPropertiesValidationResult.java
+++ b/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/ConfigurationPropertiesValidationResult.java
@@ -26,20 +26,44 @@ import java.util.Map;
  */
 public class ConfigurationPropertiesValidationResult extends PropertiesValidationResult implements Serializable {
 
-    private String key;
-    private String value;
+    private String fileName;
+    private String text;
+    private int lineNumber;
+    private boolean accepted;
 
-    public ConfigurationPropertiesValidationResult(String key, String value) {
-        this.key = key;
-        this.value = value;
+    public ConfigurationPropertiesValidationResult() {
     }
 
-    public String getKey() {
-        return key;
+    public String getFileName() {
+        return fileName;
     }
 
-    public String getValue() {
-        return value;
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public void setLineNumber(int lineNumber) {
+        this.lineNumber = lineNumber;
+    }
+
+    public boolean isAccepted() {
+        return accepted;
+    }
+
+    public void setAccepted(boolean accepted) {
+        this.accepted = accepted;
     }
 
     /**
@@ -204,13 +228,25 @@ public class ConfigurationPropertiesValidationResult extends PropertiesValidatio
             sb.append("---------------------------------------------------------------------------------------------------------------------------------------\n");
             sb.append("\n");
         }
-        sb.append("\n");
+        if (text != null) {
+            sb.append("\t").append(text).append("\n");
+        } else {
+            sb.append("\n");
+        }
         for (Map.Entry<String, String> option : options.entrySet()) {
-            String out = String.format(format, option.getKey(), option.getValue());
+            String out = String.format(format, shortKey(option.getKey()), option.getValue());
             sb.append("\n\t").append(out);
         }
 
         return sb.toString();
     }
 
+    private static String shortKey(String key) {
+        if (key.indexOf('.') > 0) {
+            return key.substring(key.lastIndexOf('.') + 1);
+        } else {
+            return key;
+        }
+    }
+
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/JSonSchemaResolver.java b/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/JSonSchemaResolver.java
index a849b0b..1dba046 100644
--- a/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/JSonSchemaResolver.java
+++ b/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/JSonSchemaResolver.java
@@ -22,6 +22,11 @@ package org.apache.camel.runtimecatalog;
 public interface JSonSchemaResolver {
 
     /**
+     * Sets an extra class loader to use first for loading resources.
+     */
+    void setClassLoader(ClassLoader classLoader);
+
+    /**
      * Returns the component information as JSon format.
      *
      * @param name the component name
diff --git a/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/RuntimeCamelCatalog.java b/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/RuntimeCamelCatalog.java
index 8228595..ccd0675 100644
--- a/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/RuntimeCamelCatalog.java
+++ b/core/camel-api/src/main/java/org/apache/camel/runtimecatalog/RuntimeCamelCatalog.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.runtimecatalog;
 
+import java.io.InputStream;
 import java.net.URISyntaxException;
 import java.util.Map;
 
@@ -172,10 +173,10 @@ public interface RuntimeCamelCatalog extends StaticService {
     /**
      * Parses and validates the configuration property
      *
-     * @param text  the configuration text
+     * @param line  the configuration line as key=value
      * @return validation result
      */
-    ConfigurationPropertiesValidationResult validateConfigurationProperty(String text);
+    ConfigurationPropertiesValidationResult validateConfigurationProperty(String line);
 
     /**
      * Returns the component name from the given endpoint uri
diff --git a/core/camel-base/src/main/java/org/apache/camel/runtimecatalog/impl/AbstractCamelCatalog.java b/core/camel-base/src/main/java/org/apache/camel/runtimecatalog/impl/AbstractCamelCatalog.java
index 2e06468..4b3bdbe 100644
--- a/core/camel-base/src/main/java/org/apache/camel/runtimecatalog/impl/AbstractCamelCatalog.java
+++ b/core/camel-base/src/main/java/org/apache/camel/runtimecatalog/impl/AbstractCamelCatalog.java
@@ -1019,16 +1019,18 @@ public abstract class AbstractCamelCatalog {
         return tokens.toArray(new String[tokens.size()]);
     }
 
-    public ConfigurationPropertiesValidationResult validateConfigurationProperty(String text) {
-        String longKey = before(text, "=");
+    public ConfigurationPropertiesValidationResult validateConfigurationProperty(String line) {
+        String longKey = before(line, "=");
         String key = longKey;
-        String value = after(text, "=");
+        String value = after(line, "=");
 
-        ConfigurationPropertiesValidationResult result = new ConfigurationPropertiesValidationResult(key, value);
+        ConfigurationPropertiesValidationResult result = new ConfigurationPropertiesValidationResult();
         boolean accept = acceptConfigurationPropertyKey(key);
         if (!accept) {
-            result.addUnknown(key);
+            result.setAccepted(false);
             return result;
+        } else {
+            result.setAccepted(true);
         }
 
         boolean component = key.startsWith("camel.component.");
diff --git a/core/camel-base/src/main/java/org/apache/camel/runtimecatalog/impl/CamelContextJSonSchemaResolver.java b/core/camel-base/src/main/java/org/apache/camel/runtimecatalog/impl/CamelContextJSonSchemaResolver.java
index 9e92aa5..c24b89d 100644
--- a/core/camel-base/src/main/java/org/apache/camel/runtimecatalog/impl/CamelContextJSonSchemaResolver.java
+++ b/core/camel-base/src/main/java/org/apache/camel/runtimecatalog/impl/CamelContextJSonSchemaResolver.java
@@ -30,6 +30,7 @@ import org.apache.camel.util.IOHelper;
  */
 public class CamelContextJSonSchemaResolver implements JSonSchemaResolver {
 
+    private ClassLoader classLoader;
     private final CatalogCamelContext camelContext;
 
     public CamelContextJSonSchemaResolver(CamelContext camelContext) {
@@ -37,6 +38,11 @@ public class CamelContextJSonSchemaResolver implements JSonSchemaResolver {
     }
 
     @Override
+    public void setClassLoader(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
+    @Override
     public String getComponentJSonSchema(String name) {
         try {
             return camelContext.getComponentParameterJsonSchema(name);
@@ -85,15 +91,21 @@ public class CamelContextJSonSchemaResolver implements JSonSchemaResolver {
     @Override
     public String getMainJsonSchema() {
         String path = "META-INF/camel-main-configuration-metadata.json";
-        ClassResolver resolver = camelContext.getClassResolver();
-        InputStream inputStream = resolver.loadResourceAsStream(path);
-        if (inputStream != null) {
+        InputStream is = null;
+        if (classLoader != null) {
+            is = classLoader.getResourceAsStream(path);
+        }
+        if (is == null) {
+            ClassResolver resolver = camelContext.getClassResolver();
+            is = resolver.loadResourceAsStream(path);
+        }
+        if (is != null) {
             try {
-                return IOHelper.loadText(inputStream);
+                return IOHelper.loadText(is);
             } catch (IOException e) {
                 // ignore
             } finally {
-                IOHelper.close(inputStream);
+                IOHelper.close(is);
             }
         }
         return null;
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/JSonSchemaHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/JSonSchemaHelper.java
index fc90ac9..18fd528 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/JSonSchemaHelper.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/JSonSchemaHelper.java
@@ -33,6 +33,8 @@ import org.apache.camel.util.json.Jsoner;
  */
 public final class JSonSchemaHelper {
 
+    private static final String[] LOGGING_LEVELS = new String[]{"ERROR", "WARN", "INFO", "DEBUG", "TRACE", "OFF"};
+
     private JSonSchemaHelper() {
     }
 
@@ -70,6 +72,16 @@ public final class JSonSchemaHelper {
                         String type = newRow.get("type");
                         newRow.put("javaType", type);
                         newRow.put("type", fromMainToType(type));
+                        // add known enums
+                        if ("org.apache.camel.LoggingLevel".equals(type)) {
+                            newRow.put("enum", "ERROR,WARN,INFO,DEBUG,TRACE,OFF");
+                        } else if ("org.apache.camel.ManagementStatisticsLevel".equals(type)) {
+                            newRow.put("enum", "Extended,Default,RoutesOnly,Off");
+                        } else if ("org.apache.camel.spi.RestBindingMode".equals(type)) {
+                            newRow.put("enum", "auto,off,json,xml,json_xml");
+                        } else if ("org.apache.camel.spi.RestHostNameResolver".equals(type)) {
+                            newRow.put("enum", "allLocalIp,localIp,localHostName");
+                        }
                     }
                 }
             }
diff --git a/docs/components/modules/ROOT/nav.adoc b/docs/components/modules/ROOT/nav.adoc
index 062b16a..0b5c531 100644
--- a/docs/components/modules/ROOT/nav.adoc
+++ b/docs/components/modules/ROOT/nav.adoc
@@ -6,7 +6,6 @@
 * xref:ahc-component.adoc[AHC Component]
 * xref:amqp-component.adoc[AMQP Component]
 * xref:any23-dataformat.adoc[Any23 DataFormat]
-* xref:any23-dataformat.adoc[Any23 DataFormat]
 * xref:apns-component.adoc[APNS Component]
 * xref:as2-component.adoc[AS2 Component]
 * xref:asn1-dataformat.adoc[ASN.1 File DataFormat]
@@ -43,7 +42,6 @@
 * xref:aws-sqs-component.adoc[AWS Simple Queue Service Component]
 * xref:aws-swf-component.adoc[AWS Simple Workflow Component]
 * xref:aws-translate-component.adoc[AWS Translate Component]
-* xref:aws-translate-component.adoc[AWS Translate Component]
 * xref:aws-xray.adoc[AWS XRay Component]
 * xref:azure-blob-component.adoc[Azure Storage Blob Service Component]
 * xref:azure-queue-component.adoc[Azure Storage Queue Service Component]
diff --git a/docs/components/modules/ROOT/pages/any23-dataformat.adoc b/docs/components/modules/ROOT/pages/any23-dataformat.adoc
index 7edf558..b1c0cc5 100644
--- a/docs/components/modules/ROOT/pages/any23-dataformat.adoc
+++ b/docs/components/modules/ROOT/pages/any23-dataformat.adoc
@@ -1,6 +1,6 @@
 [[any23-dataformat]]
 = Any23 DataFormat
-:page-source: components/camel-any23/bin/src/main/docs/any23-dataformat.adoc
+:page-source: components/camel-any23/src/main/docs/any23-dataformat.adoc
 Camel Any23 is a DataFormat that uses the Apache Anything To Triples (Any23) library to extract structured data in RDF from a variety of documents on the web.
 *Since Camel 3.0*
 
diff --git a/docs/components/modules/ROOT/pages/aws-translate-component.adoc b/docs/components/modules/ROOT/pages/aws-translate-component.adoc
index 98e17c2..380328c 100644
--- a/docs/components/modules/ROOT/pages/aws-translate-component.adoc
+++ b/docs/components/modules/ROOT/pages/aws-translate-component.adoc
@@ -1,6 +1,6 @@
 [[aws-translate-component]]
 = AWS Translate Component
-:page-source: components/camel-aws-translate/bin/src/main/docs/aws-translate-component.adoc
+:page-source: components/camel-aws-translate/src/main/docs/aws-translate-component.adoc
 
 *Since Camel 3.0*
 
@@ -70,7 +70,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (12 parameters):
+=== Query Parameters (14 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -85,6 +85,8 @@ with the following path and query parameters:
 | *proxyProtocol* (producer) | To define a proxy protocol when instantiating the Translate client | HTTPS | Protocol
 | *region* (producer) | The region in which Translate client needs to work. When using this parameter, the configuration will expect the capitalized name of the region (for example AP_EAST_1) You'll need to use the name Regions.EU_WEST_1.name() |  | String
 | *secretKey* (producer) | Amazon AWS Secret Key |  | String
+| *sourceLanguage* (producer) | Source language to use |  | String
+| *targetLanguage* (producer) | Target language to use |  | String
 | *translateClient* (producer) | To use a existing configured AWS Translate as client |  | AmazonTranslate
 | *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
 | *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean