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:06 UTC

[camel] branch master updated (af56387 -> 278c382)

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

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


    from af56387  Upgrade Json Schema validator to version 1.0.29
     new 4bcc61b  CAMEL-14311: Add validate configuration properties to camel-catalog.
     new 30117b0  CAMEL-14311: Add validate configuration properties to camel-catalog.
     new 278c382  Regen

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../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  | 215 ++++++++++++++++++-
 .../ConfigurationPropertiesValidationResult.java   | 229 ++++++++++++++++++++-
 .../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 +-
 .../modules/ROOT/pages/osgi-activator.adoc         |  17 ++
 14 files changed, 517 insertions(+), 33 deletions(-)


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

Posted by da...@apache.org.
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


[camel] 03/03: Regen

Posted by da...@apache.org.
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 278c3821ecb64d8577bf4ce0fe88228842eae4eb
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Dec 23 10:52:39 2019 +0100

    Regen
---
 docs/components/modules/ROOT/pages/osgi-activator.adoc | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/docs/components/modules/ROOT/pages/osgi-activator.adoc b/docs/components/modules/ROOT/pages/osgi-activator.adoc
index 00438d2..e4de6bb 100644
--- a/docs/components/modules/ROOT/pages/osgi-activator.adoc
+++ b/docs/components/modules/ROOT/pages/osgi-activator.adoc
@@ -55,3 +55,20 @@ And it's automatically added or removed to the context from any bundle!
 ----
 Route: route1 started and consuming from: timer://test?fixedRate=true&period=1000
 ----
+
+For routes that need to be started before the CamelContext the "camel.osgi.activator.pre-startup" service property may be added.  
+
+[source,java]
+----
+@Component(service = RouteBuilder.class, property = {CamelRoutesActivatorConstants.PRE_START_UP_PROP_NAME + "=true"})
+public class MyStartupRouteBuilder extends RouteBuilder {
+    @Override
+    public void configure() throws Exception {
+        getContext().setStreamCaching(true);
+
+        restConfiguration().component("netty-http").port(8080);
+    }
+}
+----
+
+If this RouteBuilder is added after other non pre startup RouteBuilders then CamelContext will automatically restart.  This allows pre start up RouteBuilder to run their configure methods before other RouteBuilders.


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

Posted by da...@apache.org.
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 4bcc61bc34ba284c4a575ff7f038e7948a33b899
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Dec 22 08:51:43 2019 +0100

    CAMEL-14311: Add validate configuration properties to camel-catalog.
---
 .../java/org/apache/camel/maven/ValidateMojo.java  |  84 +++++++++-
 .../ConfigurationPropertiesValidationResult.java   | 175 +++++++++++++++++++++
 2 files changed, 255 insertions(+), 4 deletions(-)

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 8f17ace..ea10bd2 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
@@ -22,9 +22,11 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
 import java.util.List;
+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.DefaultCamelCatalog;
 import org.apache.camel.catalog.EndpointValidationResult;
@@ -37,6 +39,8 @@ import org.apache.camel.parser.model.CamelEndpointDetails;
 import org.apache.camel.parser.model.CamelRouteDetails;
 import org.apache.camel.parser.model.CamelSimpleExpressionDetails;
 import org.apache.camel.support.PatternHelper;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.OrderedProperties;
 import org.apache.camel.util.StringHelper;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.Resource;
@@ -51,7 +55,8 @@ import org.jboss.forge.roaster.model.JavaType;
 import org.jboss.forge.roaster.model.source.JavaClassSource;
 
 /**
- * Parses the source code and validates the Camel routes has valid endpoint uris and simple expressions.
+ * Parses the source code and validates the Camel routes has valid endpoint uris and simple expressions,
+ * and validates configuration files such as application.properties.
  */
 @Mojo(name = "validate", threadSafe = true)
 public class ValidateMojo extends AbstractExecMojo {
@@ -158,6 +163,13 @@ public class ValidateMojo extends AbstractExecMojo {
     @Parameter(property = "camel.directOrSedaPairCheck", defaultValue = "true")
     private boolean directOrSedaPairCheck;
 
+    /**
+     * Location of configuration files to validate. The default is application.properties
+     * Multiple values can be separated by comma and use ANT path style.
+     */
+    @Parameter(property = "camel.configurationFiles")
+    private String configurationFiles = "application.properties";
+
     // CHECKSTYLE:OFF
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
@@ -195,6 +207,45 @@ public class ValidateMojo extends AbstractExecMojo {
             getLog().info("Validating using Camel version: " + catalog.getCatalogVersion());
         }
 
+        doExecuteRoutes(catalog);
+        doExecuteConfigurationFiles(catalog);
+    }
+
+    protected void doExecuteConfigurationFiles(CamelCatalog catalog) {
+        // 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);
+        }
+        if (includeTest) {
+            list = project.getTestResources();
+            for (Object obj : list) {
+                String dir = (String) obj;
+                findPropertiesFiles(new File(dir), propertiesFiles);
+            }
+        }
+        for (File file : propertiesFiles) {
+            if (matchPropertiesFile(file)) {
+                InputStream is = null;
+                try {
+                    is = new FileInputStream(file);
+                    Properties prop = new OrderedProperties();
+                    prop.load(is);
+
+                    EndpointValidationResult result = catalog.validateConfigurationProperty(line);
+                } catch (Exception e) {
+                    getLog().warn("Error parsing file " + file + " code due " + e.getMessage(), e);
+                } finally {
+                    IOHelper.close(is);
+                }
+            }
+        }
+    }
+
+    protected void doExecuteRoutes(CamelCatalog catalog) throws MojoExecutionException, MojoFailureException {
         List<CamelEndpointDetails> endpoints = new ArrayList<>();
         List<CamelSimpleExpressionDetails> simpleExpressions = new ArrayList<>();
         List<CamelRouteDetails> routeIds = new ArrayList<>();
@@ -233,7 +284,7 @@ public class ValidateMojo extends AbstractExecMojo {
         }
 
         for (File file : javaFiles) {
-            if (matchFile(file)) {
+            if (matchRouteFile(file)) {
                 try {
                     List<CamelEndpointDetails> fileEndpoints = new ArrayList<>();
                     List<CamelRouteDetails> fileRouteIds = new ArrayList<>();
@@ -271,7 +322,7 @@ public class ValidateMojo extends AbstractExecMojo {
             }
         }
         for (File file : xmlFiles) {
-            if (matchFile(file)) {
+            if (matchRouteFile(file)) {
                 try {
                     List<CamelEndpointDetails> fileEndpoints = new ArrayList<>();
                     List<CamelSimpleExpressionDetails> fileSimpleExpressions = new ArrayList<>();
@@ -773,6 +824,19 @@ public class ValidateMojo extends AbstractExecMojo {
         return null;
     }
 
+    private void findPropertiesFiles(File dir, Set<File> propertiesFiles) {
+        File[] files = dir.isDirectory() ? dir.listFiles() : null;
+        if (files != null) {
+            for (File file : files) {
+                if (file.getName().endsWith(".properties")) {
+                    propertiesFiles.add(file);
+                } else if (file.isDirectory()) {
+                    findJavaFiles(file, propertiesFiles);
+                }
+            }
+        }
+    }
+
     private void findJavaFiles(File dir, Set<File> javaFiles) {
         File[] files = dir.isDirectory() ? dir.listFiles() : null;
         if (files != null) {
@@ -799,7 +863,19 @@ public class ValidateMojo extends AbstractExecMojo {
         }
     }
 
-    private boolean matchFile(File file) {
+    private boolean matchPropertiesFile(File file) {
+        for (String part : configurationFiles.split(",")) {
+            part = part.trim();
+            String fqn = stripRootPath(asRelativeFile(file.getAbsolutePath()));
+            boolean match = PatternHelper.matchPattern(fqn, part);
+            if (match) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean matchRouteFile(File file) {
         if (excludes == null && includes == null) {
             return true;
         }
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 16a40d1..8138445 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
@@ -17,6 +17,9 @@
 package org.apache.camel.runtimecatalog;
 
 import java.io.Serializable;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
 /**
  * Details result of validating configuration properties (eg application.properties for camel-main).
@@ -38,4 +41,176 @@ public class ConfigurationPropertiesValidationResult extends PropertiesValidatio
     public String getValue() {
         return value;
     }
+
+    /**
+     * A human readable summary of the validation errors.
+     *
+     * @param includeHeader    whether to include a header
+     * @return the summary, or <tt>null</tt> if no validation errors
+     */
+    public String summaryErrorMessage(boolean includeHeader) {
+        return summaryErrorMessage(includeHeader, true, false);
+    }
+
+    /**
+     * A human readable summary of the validation errors.
+     *
+     * @param includeHeader    whether to include a header
+     * @param ignoreDeprecated whether to ignore deprecated options in use as an error or not
+     * @param includeWarnings  whether to include warnings as an error or not
+     * @return the summary, or <tt>null</tt> if no validation errors
+     */
+    public String summaryErrorMessage(boolean includeHeader, boolean ignoreDeprecated, boolean includeWarnings) {
+        boolean ok = isSuccess();
+
+        // special check if we should ignore deprecated options being used
+        if (ok && !ignoreDeprecated) {
+            ok = deprecated == null;
+        }
+
+        if (includeWarnings) {
+            if (unknownComponent != null) {
+                return "\tUnknown component: " + unknownComponent;
+            }
+        }
+
+        if (ok) {
+            return null;
+        }
+
+        // for each invalid option build a reason message
+        Map<String, String> options = new LinkedHashMap<>();
+        if (unknown != null) {
+            for (String name : unknown) {
+                if (unknownSuggestions != null && unknownSuggestions.containsKey(name)) {
+                    String[] suggestions = unknownSuggestions.get(name);
+                    if (suggestions != null && suggestions.length > 0) {
+                        String str = Arrays.asList(suggestions).toString();
+                        options.put(name, "Unknown option. Did you mean: " + str);
+                    } else {
+                        options.put(name, "Unknown option");
+                    }
+                } else {
+                    options.put(name, "Unknown option");
+                }
+            }
+        }
+        if (required != null) {
+            for (String name : required) {
+                options.put(name, "Missing required option");
+            }
+        }
+        if (deprecated != null) {
+            for (String name : deprecated) {
+                options.put(name, "Deprecated option");
+            }
+        }
+        if (invalidEnum != null) {
+            for (Map.Entry<String, String> entry : invalidEnum.entrySet()) {
+                String name = entry.getKey();
+                String[] choices = invalidEnumChoices.get(name);
+                String defaultValue = defaultValues != null ? defaultValues.get(entry.getKey()) : null;
+                String str = Arrays.asList(choices).toString();
+                String msg = "Invalid enum value: " + entry.getValue() + ". Possible values: " + str;
+                if (invalidEnumSuggestions != null) {
+                    String[] suggestions = invalidEnumSuggestions.get(name);
+                    if (suggestions != null && suggestions.length > 0) {
+                        str = Arrays.asList(suggestions).toString();
+                        msg += ". Did you mean: " + str;
+                    }
+                }
+                if (defaultValue != null) {
+                    msg += ". Default value: " + defaultValue;
+                }
+
+                options.put(entry.getKey(), msg);
+            }
+        }
+        if (invalidReference != null) {
+            for (Map.Entry<String, String> entry : invalidReference.entrySet()) {
+                boolean empty = isEmpty(entry.getValue());
+                if (empty) {
+                    options.put(entry.getKey(), "Empty reference value");
+                } else if (!entry.getValue().startsWith("#")) {
+                    options.put(entry.getKey(), "Invalid reference value: " + entry.getValue() + " must start with #");
+                } else {
+                    options.put(entry.getKey(), "Invalid reference value: " + entry.getValue());
+                }
+            }
+        }
+        if (invalidBoolean != null) {
+            for (Map.Entry<String, String> entry : invalidBoolean.entrySet()) {
+                boolean empty = isEmpty(entry.getValue());
+                if (empty) {
+                    options.put(entry.getKey(), "Empty boolean value");
+                } else {
+                    options.put(entry.getKey(), "Invalid boolean value: " + entry.getValue());
+                }
+            }
+        }
+        if (invalidInteger != null) {
+            for (Map.Entry<String, String> entry : invalidInteger.entrySet()) {
+                boolean empty = isEmpty(entry.getValue());
+                if (empty) {
+                    options.put(entry.getKey(), "Empty integer value");
+                } else {
+                    options.put(entry.getKey(), "Invalid integer value: " + entry.getValue());
+                }
+            }
+        }
+        if (invalidNumber != null) {
+            for (Map.Entry<String, String> entry : invalidNumber.entrySet()) {
+                boolean empty = isEmpty(entry.getValue());
+                if (empty) {
+                    options.put(entry.getKey(), "Empty number value");
+                } else {
+                    options.put(entry.getKey(), "Invalid number value: " + entry.getValue());
+                }
+            }
+        }
+        if (invalidMap != null) {
+            for (Map.Entry<String, String> entry : invalidMap.entrySet()) {
+                boolean empty = isEmpty(entry.getValue());
+                if (empty) {
+                    options.put(entry.getKey(), "Empty map key/value pair");
+                } else {
+                    options.put(entry.getKey(), "Invalid map key/value: " + entry.getValue());
+                }
+            }
+        }
+        if (invalidArray != null) {
+            for (Map.Entry<String, String> entry : invalidArray.entrySet()) {
+                boolean empty = isEmpty(entry.getValue());
+                if (empty) {
+                    options.put(entry.getKey(), "Empty array index/value pair");
+                } else {
+                    options.put(entry.getKey(), "Invalid array index/value: " + entry.getValue());
+                }
+            }
+        }
+
+        // build a table with the error summary nicely formatted
+        // lets use 24 as min length
+        int maxLen = 24;
+        for (String key : options.keySet()) {
+            maxLen = Math.max(maxLen, key.length());
+        }
+        String format = "%" + maxLen + "s    %s";
+
+        // build the human error summary
+        StringBuilder sb = new StringBuilder();
+        if (includeHeader) {
+            sb.append("Configuration properties error\n");
+            sb.append("---------------------------------------------------------------------------------------------------------------------------------------\n");
+            sb.append("\n");
+        }
+        sb.append("\n");
+        for (Map.Entry<String, String> option : options.entrySet()) {
+            String out = String.format(format, option.getKey(), option.getValue());
+            sb.append("\n\t").append(out);
+        }
+
+        return sb.toString();
+    }
+
 }