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 2015/03/18 16:51:25 UTC

[2/2] camel git commit: CAMEL-8509: camel-catalog - Add api to parse endpoint uri and reverse

CAMEL-8509: camel-catalog - Add api to parse endpoint uri and reverse


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

Branch: refs/heads/master
Commit: d0597fefd54392f640dcc751a328841f052799bf
Parents: 014ecdb
Author: Claus Ibsen <da...@apache.org>
Authored: Wed Mar 18 15:51:31 2015 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Mar 18 16:53:14 2015 +0100

----------------------------------------------------------------------
 .../org/apache/camel/catalog/CamelCatalog.java  |  30 ++
 .../org/apache/camel/catalog/CatalogHelper.java | 101 ++++++
 .../camel/catalog/DefaultCamelCatalog.java      | 217 ++++++++----
 .../org/apache/camel/catalog/URISupport.java    | 331 +++++++++++++++++++
 .../apache/camel/catalog/CamelCatalogTest.java  |  36 ++
 .../catalog/src/test/resources/sample.json      |  92 ++++++
 6 files changed, 738 insertions(+), 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/d0597fef/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelCatalog.java
----------------------------------------------------------------------
diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelCatalog.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelCatalog.java
index 3826063..f71fb8e 100644
--- a/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelCatalog.java
+++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelCatalog.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.catalog;
 
+import java.net.URISyntaxException;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import javax.management.MXBean;
 
@@ -146,4 +148,32 @@ public interface CamelCatalog {
      * @return the blueprint XML schema
      */
     String blueprintSchemaAsXml();
+
+    /**
+     * Parses the endpoint uri and constructs a key/value properties of each option
+     *
+     * @param uri  the endpoint uri
+     * @return properties as key value pairs of each endpoint option
+     */
+    Map<String, String> endpointProperties(String uri) throws URISyntaxException;
+
+    /**
+     * Creates an endpoint uri from the information in the json schema
+     *
+     * @param scheme the endpoint schema
+     * @param json the json schema with the endpoint properties
+     * @return the constructed endpoint uri
+     * @throws java.net.URISyntaxException is thrown if there is encoding error
+     */
+    String asEndpointUri(String scheme, String json) throws URISyntaxException;
+
+    /**
+     * Creates an endpoint uri from the information from the properties
+     *
+     * @param scheme the endpoint schema
+     * @param properties the properties as key value pairs
+     * @return the constructed endpoint uri
+     * @throws java.net.URISyntaxException is thrown if there is encoding error
+     */
+    String asEndpointUri(String scheme, Map<String, String> properties) throws URISyntaxException;
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/d0597fef/platforms/catalog/src/main/java/org/apache/camel/catalog/CatalogHelper.java
----------------------------------------------------------------------
diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/CatalogHelper.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/CatalogHelper.java
new file mode 100644
index 0000000..e33b562
--- /dev/null
+++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/CatalogHelper.java
@@ -0,0 +1,101 @@
+/**
+ * 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.catalog;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.util.List;
+
+public final class CatalogHelper {
+
+    private CatalogHelper() {
+    }
+
+
+    /**
+     * Loads the entire stream into memory as a String and returns it.
+     * <p/>
+     * <b>Notice:</b> This implementation appends a <tt>\n</tt> as line
+     * terminator at the of the text.
+     * <p/>
+     * Warning, don't use for crazy big streams :)
+     */
+    public static void loadLines(InputStream in, List<String> lines) throws IOException {
+        InputStreamReader isr = new InputStreamReader(in);
+        try {
+            BufferedReader reader = new LineNumberReader(isr);
+            while (true) {
+                String line = reader.readLine();
+                if (line != null) {
+                    lines.add(line);
+                } else {
+                    break;
+                }
+            }
+        } finally {
+            isr.close();
+            in.close();
+        }
+    }
+
+    /**
+     * Loads the entire stream into memory as a String and returns it.
+     * <p/>
+     * <b>Notice:</b> This implementation appends a <tt>\n</tt> as line
+     * terminator at the of the text.
+     * <p/>
+     * Warning, don't use for crazy big streams :)
+     */
+    public static String loadText(InputStream in) throws IOException {
+        StringBuilder builder = new StringBuilder();
+        InputStreamReader isr = new InputStreamReader(in);
+        try {
+            BufferedReader reader = new LineNumberReader(isr);
+            while (true) {
+                String line = reader.readLine();
+                if (line != null) {
+                    builder.append(line);
+                    builder.append("\n");
+                } else {
+                    break;
+                }
+            }
+            return builder.toString();
+        } finally {
+            isr.close();
+            in.close();
+        }
+    }
+
+    /**
+     * Matches the name with the pattern.
+     *
+     * @param name  the name
+     * @param pattern the pattern
+     * @return <tt>true</tt> if matched, or <tt>false</tt> if not
+     */
+    public static boolean matchWildcard(String name, String pattern) {
+        // we have wildcard support in that hence you can match with: file* to match any file endpoints
+        if (pattern.endsWith("*") && name.startsWith(pattern.substring(0, pattern.length() - 1))) {
+            return true;
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d0597fef/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java
----------------------------------------------------------------------
diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java
index ec94fce..321b035 100644
--- a/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java
+++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelCatalog.java
@@ -16,19 +16,24 @@
  */
 package org.apache.camel.catalog;
 
-import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.LineNumberReader;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 
+import static org.apache.camel.catalog.URISupport.createQueryString;
+
 /**
  * Default {@link CamelCatalog}.
  */
@@ -45,6 +50,8 @@ public class DefaultCamelCatalog implements CamelCatalog {
     private static final String ARCHETYPES_CATALOG = "org/apache/camel/catalog/archetypes/archetype-catalog.xml";
     private static final String SCHEMAS_XML = "org/apache/camel/catalog/schemas";
 
+    private static final Pattern SYNTAX_PATTERN = Pattern.compile("(\\w+)");
+
     @Override
     public List<String> findComponentNames() {
         List<String> names = new ArrayList<String>();
@@ -52,7 +59,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(COMPONENTS_CATALOG);
         if (is != null) {
             try {
-                loadLines(is, names);
+                CatalogHelper.loadLines(is, names);
             } catch (IOException e) {
                 // ignore
             }
@@ -67,7 +74,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(DATA_FORMATS_CATALOG);
         if (is != null) {
             try {
-                loadLines(is, names);
+                CatalogHelper.loadLines(is, names);
             } catch (IOException e) {
                 // ignore
             }
@@ -82,7 +89,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(LANGUAGE_CATALOG);
         if (is != null) {
             try {
-                loadLines(is, names);
+                CatalogHelper.loadLines(is, names);
             } catch (IOException e) {
                 // ignore
             }
@@ -97,7 +104,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(MODELS_CATALOG);
         if (is != null) {
             try {
-                loadLines(is, names);
+                CatalogHelper.loadLines(is, names);
             } catch (IOException e) {
                 // ignore
             }
@@ -120,7 +127,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
                         String[] parts = label.split(",");
                         for (String part : parts) {
                             try {
-                                if (part.equalsIgnoreCase(filter) || matchWildcard(part, filter) || part.matches(filter)) {
+                                if (part.equalsIgnoreCase(filter) || CatalogHelper.matchWildcard(part, filter) || part.matches(filter)) {
                                     answer.add(name);
                                 }
                             } catch (PatternSyntaxException e) {
@@ -150,7 +157,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
                         String[] parts = label.split(",");
                         for (String part : parts) {
                             try {
-                                if (part.equalsIgnoreCase(filter) || matchWildcard(part, filter) || part.matches(filter)) {
+                                if (part.equalsIgnoreCase(filter) || CatalogHelper.matchWildcard(part, filter) || part.matches(filter)) {
                                     answer.add(name);
                                 }
                             } catch (PatternSyntaxException e) {
@@ -180,7 +187,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
                         String[] parts = label.split(",");
                         for (String part : parts) {
                             try {
-                                if (part.equalsIgnoreCase(filter) || matchWildcard(part, filter) || part.matches(filter)) {
+                                if (part.equalsIgnoreCase(filter) || CatalogHelper.matchWildcard(part, filter) || part.matches(filter)) {
                                     answer.add(name);
                                 }
                             } catch (PatternSyntaxException e) {
@@ -210,7 +217,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
                         String[] parts = label.split(",");
                         for (String part : parts) {
                             try {
-                                if (part.equalsIgnoreCase(filter) || matchWildcard(part, filter) || part.matches(filter)) {
+                                if (part.equalsIgnoreCase(filter) || CatalogHelper.matchWildcard(part, filter) || part.matches(filter)) {
                                     answer.add(name);
                                 }
                             } catch (PatternSyntaxException e) {
@@ -232,7 +239,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(file);
         if (is != null) {
             try {
-                return loadText(is);
+                return CatalogHelper.loadText(is);
             } catch (IOException e) {
                 // ignore
             }
@@ -248,7 +255,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(file);
         if (is != null) {
             try {
-                return loadText(is);
+                return CatalogHelper.loadText(is);
             } catch (IOException e) {
                 // ignore
             }
@@ -264,7 +271,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(file);
         if (is != null) {
             try {
-                return loadText(is);
+                return CatalogHelper.loadText(is);
             } catch (IOException e) {
                 // ignore
             }
@@ -280,7 +287,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(file);
         if (is != null) {
             try {
-                return loadText(is);
+                return CatalogHelper.loadText(is);
             } catch (IOException e) {
                 // ignore
             }
@@ -392,7 +399,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(file);
         if (is != null) {
             try {
-                return loadText(is);
+                return CatalogHelper.loadText(is);
             } catch (IOException e) {
                 // ignore
             }
@@ -408,7 +415,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(file);
         if (is != null) {
             try {
-                return loadText(is);
+                return CatalogHelper.loadText(is);
             } catch (IOException e) {
                 // ignore
             }
@@ -424,7 +431,7 @@ public class DefaultCamelCatalog implements CamelCatalog {
         InputStream is = DefaultCamelCatalog.class.getClassLoader().getResourceAsStream(file);
         if (is != null) {
             try {
-                return loadText(is);
+                return CatalogHelper.loadText(is);
             } catch (IOException e) {
                 // ignore
             }
@@ -433,67 +440,139 @@ public class DefaultCamelCatalog implements CamelCatalog {
         return null;
     }
 
-    /**
-     * Loads the entire stream into memory as a String and returns it.
-     * <p/>
-     * <b>Notice:</b> This implementation appends a <tt>\n</tt> as line
-     * terminator at the of the text.
-     * <p/>
-     * Warning, don't use for crazy big streams :)
-     */
-    private static void loadLines(InputStream in, List<String> lines) throws IOException {
-        InputStreamReader isr = new InputStreamReader(in);
-        try {
-            BufferedReader reader = new LineNumberReader(isr);
-            while (true) {
-                String line = reader.readLine();
-                if (line != null) {
-                    lines.add(line);
-                } else {
-                    break;
-                }
+    @Override
+    public Map<String, String> endpointProperties(String uri) throws URISyntaxException {
+        // parse the uri
+        URI u = new URI(uri);
+        String scheme = u.getScheme();
+
+        String json = componentJSonSchema(scheme);
+        if (json == null) {
+            throw new IllegalArgumentException("Cannot find endpoint with scheme " + scheme);
+        }
+
+        // grab the syntax
+        String syntax = null;
+        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("component", json, false);
+        for (Map<String, String> row : rows) {
+            if (row.containsKey("syntax")) {
+                syntax = row.get("syntax");
+                break;
+            }
+        }
+        if (syntax == null) {
+            throw new IllegalArgumentException("Endpoint with scheme " + scheme + " has no syntax defined in the json schema");
+        }
+
+        // grab the json schema for the endpoint properties
+       // rows = JSonSchemaHelper.parseJsonSchema("properties", json, true);
+
+        // now parse the uri to know which part isw what
+        Map<String, String> answer = new LinkedHashMap<String, String>();
+
+        // parse the syntax and find the same group in the uri
+
+        Matcher matcher = SYNTAX_PATTERN.matcher(syntax);
+        Matcher matcher2 = SYNTAX_PATTERN.matcher(uri);
+        while (matcher.find() && matcher2.find()) {
+            String word = matcher.group(1);
+            String word2 = matcher2.group(1);
+            // skip the scheme as we know that already
+            if (!scheme.equals(word)) {
+                answer.put(word, word2);
             }
-        } finally {
-            isr.close();
-            in.close();
         }
+
+        // now parse the uri parameters
+        Map<String, Object> parameters = URISupport.parseParameters(u);
+
+        // and covert the values to String so its JMX friendly
+        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue() != null ? entry.getValue().toString() : "";
+            answer.put(key, value);
+        }
+
+        return answer;
     }
 
-    /**
-     * Loads the entire stream into memory as a String and returns it.
-     * <p/>
-     * <b>Notice:</b> This implementation appends a <tt>\n</tt> as line
-     * terminator at the of the text.
-     * <p/>
-     * Warning, don't use for crazy big streams :)
-     */
-    public static String loadText(InputStream in) throws IOException {
-        StringBuilder builder = new StringBuilder();
-        InputStreamReader isr = new InputStreamReader(in);
-        try {
-            BufferedReader reader = new LineNumberReader(isr);
-            while (true) {
-                String line = reader.readLine();
-                if (line != null) {
-                    builder.append(line);
-                    builder.append("\n");
-                } else {
-                    break;
+    @Override
+    public String asEndpointUri(String scheme, String json) throws URISyntaxException {
+        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("properties", json, true);
+
+        Map<String, String> copy = new HashMap<String, String>();
+        for (Map<String, String> row : rows) {
+            String name = row.get("name");
+            String required = row.get("required");
+            String value = row.get("value");
+            String defaultValue = row.get("defaultValue");
+
+            // only add if either required, or the value is != default value
+            String valueToAdd = null;
+            if ("true".equals(required)) {
+                valueToAdd = value != null ? value : defaultValue;
+                if (valueToAdd == null) {
+                    valueToAdd = "";
+                }
+            } else {
+                // if we have a value and no default then add it
+                if (value != null && defaultValue == null) {
+                    valueToAdd = value;
+                }
+                // otherwise only add if the value is != default value
+                if (value != null && defaultValue != null && !value.equals(defaultValue)) {
+                    valueToAdd = value;
                 }
             }
-            return builder.toString();
-        } finally {
-            isr.close();
-            in.close();
+
+            if (valueToAdd != null) {
+                copy.put(name, valueToAdd);
+            }
         }
+
+        return asEndpointUri(scheme, copy);
     }
 
-    private static boolean matchWildcard(String name, String pattern) {
-        // we have wildcard support in that hence you can match with: file* to match any file endpoints
-        if (pattern.endsWith("*") && name.startsWith(pattern.substring(0, pattern.length() - 1))) {
-            return true;
+    @Override
+    public String asEndpointUri(String scheme, Map<String, String> properties) throws URISyntaxException {
+        String json = componentJSonSchema(scheme);
+        if (json == null) {
+            throw new IllegalArgumentException("Cannot find endpoint with scheme " + scheme);
         }
-        return false;
+
+        // grab the syntax
+        String syntax = null;
+        List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("component", json, false);
+        for (Map<String, String> row : rows) {
+            if (row.containsKey("syntax")) {
+                syntax = row.get("syntax");
+                break;
+            }
+        }
+        if (syntax == null) {
+            throw new IllegalArgumentException("Endpoint with scheme " + scheme + " has no syntax defined in the json schema");
+        }
+
+        // build at first according to syntax
+        Map<String, String> copy = new HashMap<String, String>();
+        for (Map.Entry<String, String> entry : properties.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue() != null ? entry.getValue() : "";
+            if (syntax.contains(key)) {
+                syntax = syntax.replace(key, value);
+            } else {
+                copy.put(key, value);
+            }
+        }
+
+        StringBuilder sb = new StringBuilder(syntax);
+        if (!copy.isEmpty()) {
+            sb.append('?');
+            String query = createQueryString(copy);
+            sb.append(query);
+        }
+
+        return sb.toString();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/d0597fef/platforms/catalog/src/main/java/org/apache/camel/catalog/URISupport.java
----------------------------------------------------------------------
diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/URISupport.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/URISupport.java
new file mode 100644
index 0000000..9876568
--- /dev/null
+++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/URISupport.java
@@ -0,0 +1,331 @@
+/**
+ * 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.catalog;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Copied from org.apache.camel.util.URISupport
+ */
+public final class URISupport {
+
+    public static final String RAW_TOKEN_START = "RAW(";
+    public static final String RAW_TOKEN_END = ")";
+
+    private static final String CHARSET = "UTF-8";
+
+    private URISupport() {
+        // Helper class
+    }
+
+    /**
+     * Parses the query parameters of the uri (eg the query part).
+     *
+     * @param uri the uri
+     * @return the parameters, or an empty map if no parameters (eg never null)
+     * @throws URISyntaxException is thrown if uri has invalid syntax.
+     */
+    public static Map<String, Object> parseParameters(URI uri) throws URISyntaxException {
+        String query = uri.getQuery();
+        if (query == null) {
+            String schemeSpecificPart = uri.getSchemeSpecificPart();
+            int idx = schemeSpecificPart.indexOf('?');
+            if (idx < 0) {
+                // return an empty map
+                return new LinkedHashMap<String, Object>(0);
+            } else {
+                query = schemeSpecificPart.substring(idx + 1);
+            }
+        } else {
+            query = stripPrefix(query, "?");
+        }
+        return parseQuery(query);
+    }
+
+    /**
+     * Strips the prefix from the value.
+     * <p/>
+     * Returns the value as-is if not starting with the prefix.
+     *
+     * @param value  the value
+     * @param prefix the prefix to remove from value
+     * @return the value without the prefix
+     */
+    public static String stripPrefix(String value, String prefix) {
+        if (value != null && value.startsWith(prefix)) {
+            return value.substring(prefix.length());
+        }
+        return value;
+    }
+
+    /**
+     * Parses the query part of the uri (eg the parameters).
+     * <p/>
+     * The URI parameters will by default be URI encoded. However you can define a parameter
+     * values with the syntax: <tt>key=RAW(value)</tt> which tells Camel to not encode the value,
+     * and use the value as is (eg key=value) and the value has <b>not</b> been encoded.
+     *
+     * @param uri the uri
+     * @return the parameters, or an empty map if no parameters (eg never null)
+     * @throws URISyntaxException is thrown if uri has invalid syntax.
+     * @see #RAW_TOKEN_START
+     * @see #RAW_TOKEN_END
+     */
+    public static Map<String, Object> parseQuery(String uri) throws URISyntaxException {
+        return parseQuery(uri, false);
+    }
+
+    /**
+     * Parses the query part of the uri (eg the parameters).
+     * <p/>
+     * The URI parameters will by default be URI encoded. However you can define a parameter
+     * values with the syntax: <tt>key=RAW(value)</tt> which tells Camel to not encode the value,
+     * and use the value as is (eg key=value) and the value has <b>not</b> been encoded.
+     *
+     * @param uri the uri
+     * @param useRaw whether to force using raw values
+     * @return the parameters, or an empty map if no parameters (eg never null)
+     * @throws URISyntaxException is thrown if uri has invalid syntax.
+     * @see #RAW_TOKEN_START
+     * @see #RAW_TOKEN_END
+     */
+    public static Map<String, Object> parseQuery(String uri, boolean useRaw) throws URISyntaxException {
+        // must check for trailing & as the uri.split("&") will ignore those
+        if (uri != null && uri.endsWith("&")) {
+            throw new URISyntaxException(uri, "Invalid uri syntax: Trailing & marker found. "
+                    + "Check the uri and remove the trailing & marker.");
+        }
+
+        if (isEmpty(uri)) {
+            // return an empty map
+            return new LinkedHashMap<String, Object>(0);
+        }
+
+        // need to parse the uri query parameters manually as we cannot rely on splitting by &,
+        // as & can be used in a parameter value as well.
+
+        try {
+            // use a linked map so the parameters is in the same order
+            Map<String, Object> rc = new LinkedHashMap<String, Object>();
+
+            boolean isKey = true;
+            boolean isValue = false;
+            boolean isRaw = false;
+            StringBuilder key = new StringBuilder();
+            StringBuilder value = new StringBuilder();
+
+            // parse the uri parameters char by char
+            for (int i = 0; i < uri.length(); i++) {
+                // current char
+                char ch = uri.charAt(i);
+                // look ahead of the next char
+                char next;
+                if (i <= uri.length() - 2) {
+                    next = uri.charAt(i + 1);
+                } else {
+                    next = '\u0000';
+                }
+
+                // are we a raw value
+                isRaw = value.toString().startsWith(RAW_TOKEN_START);
+
+                // if we are in raw mode, then we keep adding until we hit the end marker
+                if (isRaw) {
+                    if (isKey) {
+                        key.append(ch);
+                    } else if (isValue) {
+                        value.append(ch);
+                    }
+
+                    // we only end the raw marker if its )& or at the end of the value
+
+                    boolean end = ch == RAW_TOKEN_END.charAt(0) && (next == '&' || next == '\u0000');
+                    if (end) {
+                        // raw value end, so add that as a parameter, and reset flags
+                        addParameter(key.toString(), value.toString(), rc, useRaw || isRaw);
+                        key.setLength(0);
+                        value.setLength(0);
+                        isKey = true;
+                        isValue = false;
+                        isRaw = false;
+                        // skip to next as we are in raw mode and have already added the value
+                        i++;
+                    }
+                    continue;
+                }
+
+                // if its a key and there is a = sign then the key ends and we are in value mode
+                if (isKey && ch == '=') {
+                    isKey = false;
+                    isValue = true;
+                    isRaw = false;
+                    continue;
+                }
+
+                // the & denote parameter is ended
+                if (ch == '&') {
+                    // parameter is ended, as we hit & separator
+                    addParameter(key.toString(), value.toString(), rc, useRaw || isRaw);
+                    key.setLength(0);
+                    value.setLength(0);
+                    isKey = true;
+                    isValue = false;
+                    isRaw = false;
+                    continue;
+                }
+
+                // regular char so add it to the key or value
+                if (isKey) {
+                    key.append(ch);
+                } else if (isValue) {
+                    value.append(ch);
+                }
+            }
+
+            // any left over parameters, then add that
+            if (key.length() > 0) {
+                addParameter(key.toString(), value.toString(), rc, useRaw || isRaw);
+            }
+
+            return rc;
+
+        } catch (UnsupportedEncodingException e) {
+            URISyntaxException se = new URISyntaxException(e.toString(), "Invalid encoding");
+            se.initCause(e);
+            throw se;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static void addParameter(String name, String value, Map<String, Object> map, boolean isRaw) throws UnsupportedEncodingException {
+        name = URLDecoder.decode(name, CHARSET);
+        if (!isRaw) {
+            // need to replace % with %25
+            value = URLDecoder.decode(value.replaceAll("%", "%25"), CHARSET);
+        }
+
+        // does the key already exist?
+        if (map.containsKey(name)) {
+            // yes it does, so make sure we can support multiple values, but using a list
+            // to hold the multiple values
+            Object existing = map.get(name);
+            List<String> list;
+            if (existing instanceof List) {
+                list = (List<String>) existing;
+            } else {
+                // create a new list to hold the multiple values
+                list = new ArrayList<String>();
+                String s = existing != null ? existing.toString() : null;
+                if (s != null) {
+                    list.add(s);
+                }
+            }
+            list.add(value);
+            map.put(name, list);
+        } else {
+            map.put(name, value);
+        }
+    }
+
+    /**
+     * Assembles a query from the given map.
+     *
+     * @param options  the map with the options (eg key/value pairs)
+     * @return a query string with <tt>key1=value&key2=value2&...</tt>, or an empty string if there is no options.
+     * @throws URISyntaxException is thrown if uri has invalid syntax.
+     */
+    @SuppressWarnings("unchecked")
+    public static String createQueryString(Map<String, String> options) throws URISyntaxException {
+        try {
+            if (options.size() > 0) {
+                StringBuilder rc = new StringBuilder();
+                boolean first = true;
+                for (Object o : options.keySet()) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        rc.append("&");
+                    }
+
+                    String key = (String) o;
+                    Object value = options.get(key);
+
+                    // use the value as a String
+                    String s = value != null ? value.toString() : null;
+                    appendQueryStringParameter(key, s, rc);
+                }
+                return rc.toString();
+            } else {
+                return "";
+            }
+        } catch (UnsupportedEncodingException e) {
+            URISyntaxException se = new URISyntaxException(e.toString(), "Invalid encoding");
+            se.initCause(e);
+            throw se;
+        }
+    }
+
+    private static void appendQueryStringParameter(String key, String value, StringBuilder rc) throws UnsupportedEncodingException {
+        rc.append(URLEncoder.encode(key, CHARSET));
+        // only append if value is not null
+        if (value != null) {
+            rc.append("=");
+            if (value.startsWith(RAW_TOKEN_START) && value.endsWith(RAW_TOKEN_END)) {
+                // do not encode RAW parameters
+                rc.append(value);
+            } else {
+                rc.append(URLEncoder.encode(value, CHARSET));
+            }
+        }
+    }
+
+    /**
+     * Tests whether the value is <tt>null</tt> or an empty string.
+     *
+     * @param value  the value, if its a String it will be tested for text length as well
+     * @return true if empty
+     */
+    public static boolean isEmpty(Object value) {
+        return !isNotEmpty(value);
+    }
+
+    /**
+     * Tests whether the value is <b>not</b> <tt>null</tt> or an empty string.
+     *
+     * @param value  the value, if its a String it will be tested for text length as well
+     * @return true if <b>not</b> empty
+     */
+    public static boolean isNotEmpty(Object value) {
+        if (value == null) {
+            return false;
+        } else if (value instanceof String) {
+            String text = (String) value;
+            return text.trim().length() > 0;
+        } else {
+            return true;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d0597fef/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java
----------------------------------------------------------------------
diff --git a/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java b/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java
index 50a55bf..93c179f 100644
--- a/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java
+++ b/platforms/catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java
@@ -16,11 +16,15 @@
  */
 package org.apache.camel.catalog;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import junit.framework.TestCase;
 import org.junit.Test;
 
+import static org.apache.camel.catalog.CatalogHelper.loadText;
+
 public class CamelCatalogTest extends TestCase {
 
     private CamelCatalog catalog = new DefaultCamelCatalog();
@@ -86,4 +90,36 @@ public class CamelCatalogTest extends TestCase {
         String schema = catalog.archetypeCatalogAsXml();
         assertNotNull(schema);
     }
+
+    @Test
+    public void testAsEndpointUriMap() throws Exception {
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("host", "someserver");
+        map.put("port", "21");
+        map.put("directoryName", "foo");
+        map.put("connectTimeout", "5000");
+
+        String uri = catalog.asEndpointUri("ftp", map);
+        assertEquals("ftp:someserver:21/foo?connectTimeout=5000", uri);
+    }
+
+    @Test
+    public void testAsEndpointUriJson() throws Exception {
+        String json = loadText(CamelCatalogTest.class.getClassLoader().getResourceAsStream("sample.json"));
+        String uri = catalog.asEndpointUri("ftp", json);
+        assertEquals("ftp:someserver:21/foo?connectTimeout=5000", uri);
+    }
+
+    @Test
+    public void testEndpointProperties() throws Exception {
+        Map<String, String> map = catalog.endpointProperties("ftp:someserver:21/foo?connectTimeout=5000");
+        assertNotNull(map);
+        assertEquals(4, map.size());
+
+        assertEquals("someserver", map.get("host"));
+        assertEquals("21", map.get("port"));
+        assertEquals("foo", map.get("directoryName"));
+        assertEquals("5000", map.get("connectTimeout"));
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/d0597fef/platforms/catalog/src/test/resources/sample.json
----------------------------------------------------------------------
diff --git a/platforms/catalog/src/test/resources/sample.json b/platforms/catalog/src/test/resources/sample.json
new file mode 100644
index 0000000..a977639
--- /dev/null
+++ b/platforms/catalog/src/test/resources/sample.json
@@ -0,0 +1,92 @@
+{
+  "properties": {
+    "host": { "value": "someserver", "kind": "path", "required": "true", "type": "string", "javaType": "java.lang.String", "deprecated": "false", "description": "Hostname of the FTP server" },
+    "port": { "value": "21", "kind": "path", "type": "integer", "javaType": "int", "deprecated": "false", "description": "Port of the FTP server" },
+    "directoryName": { "value": "foo", "kind": "path", "type": "string", "javaType": "java.lang.String", "deprecated": "false", "description": "The starting directory" },
+    "username": { "kind": "parameter", "type": "string", "javaType": "java.lang.String", "deprecated": "false", "description": "Username to use for login" },
+    "password": { "kind": "parameter", "type": "string", "javaType": "java.lang.String", "deprecated": "false", "description": "Password to use for login" },
+    "binary": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false" },
+    "passiveMode": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false", "description": "Sets passive mode connections. Default is active mode connections." },
+    "connectTimeout": { "value": "5000", "kind": "parameter", "type": "integer", "javaType": "int", "deprecated": "false", "defaultValue": "10000", "description": "Sets the connect timeout for waiting for a connection to be established Used by both FTPClient and JSCH" },
+    "timeout": { "kind": "parameter", "type": "integer", "javaType": "int", "deprecated": "false", "defaultValue": "30000", "description": "Sets the data timeout for waiting for reply Used only by FTPClient" },
+    "soTimeout": { "kind": "parameter", "type": "integer", "javaType": "int", "deprecated": "false", "description": "Sets the so timeout Used only by FTPClient" },
+    "throwExceptionOnConnectFailed": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false", "description": "Should an exception be thrown if connection failed (exhausted) By default exception is not thrown and a WARN is logged. You can use this to enable exception being thrown and handle the thrown exception from the org.apache.camel.spi.PollingConsumerPollStrategy rollback method." },
+    "siteCommand": { "kind": "parameter", "type": "string", "javaType": "java.lang.String", "deprecated": "false", "description": "Sets optional site command(s) to be executed after successful login. Multiple site commands can be separated using a new line character (\n)." },
+    "stepwise": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "true", "description": "Sets whether we should stepwise change directories while traversing file structures when downloading files or as well when uploading a file to a directory. You can disable this if you for example are in a situation where you cannot change directory on the FTP server due security reasons." },
+    "separator": { "kind": "parameter", "type": "object", "javaType": "org.apache.camel.component.file.remote.RemoteFileConfiguration.PathSeparator", "deprecated": "false", "defaultValue": "Auto", "description": "Sets the path separator to be used. UNIX = Uses unix style path separator Windows = Uses windows style path separator Auto = (is default) Use existing path separator in file name" },
+    "streamDownload": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false", "description": "Sets the download method to use when not using a local working directory. If set to true the remote files are streamed to the route as they are read. When set to false the remote files are loaded into memory before being sent into the route." },
+    "useList": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "true", "description": "Whether to allow using LIST command when downloading a file. Default is true. In some use cases you may want to download a specific file and are not allowed to use the LIST command and therefore you can set this option to false." },
+    "ignoreFileNotFoundOrPermissionError": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false", "description": "Whether to ignore when trying to download a file which does not exist or due to permission error. By default when a file does not exists or insufficient permission then an exception is thrown. Setting this option to true allows to ignore that instead." },
+    "dataTimeout": { "kind": "parameter", "type": "integer", "javaType": "int", "deprecated": "false" },
+    "maximumReconnectAttempts": { "kind": "parameter", "type": "integer", "javaType": "int", "deprecated": "false" },
+    "reconnectDelay": { "kind": "parameter", "type": "integer", "javaType": "long", "deprecated": "false" },
+    "disconnect": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false" },
+    "fastExistsCheck": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false" },
+    "download": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false" },
+    "autoCreate": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "true" },
+    "bufferSize": { "kind": "parameter", "type": "integer", "javaType": "int", "deprecated": "false", "defaultValue": "131072" },
+    "flatten": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false" },
+    "charset": { "kind": "parameter", "type": "string", "javaType": "java.lang.String", "deprecated": "false" },
+    "fileName": { "kind": "parameter", "type": "object", "javaType": "org.apache.camel.Expression", "deprecated": "false" },
+    "fileExist": { "kind": "parameter", "label": "producer", "type": "string", "javaType": "org.apache.camel.component.file.GenericFileExist", "enum": [ "Override", "Append", "Fail", "Ignore", "Move", "TryRename" ], "deprecated": "false", "defaultValue": "Override" },
+    "tempPrefix": { "kind": "parameter", "label": "producer", "type": "string", "javaType": "java.lang.String", "deprecated": "false" },
+    "tempFileName": { "kind": "parameter", "label": "producer", "type": "object", "javaType": "org.apache.camel.Expression", "deprecated": "false" },
+    "eagerDeleteTargetFile": { "kind": "parameter", "label": "producer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "true" },
+    "keepLastModified": { "kind": "parameter", "label": "producer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "false" },
+    "doneFileName": { "kind": "parameter", "label": "producer", "type": "string", "javaType": "java.lang.String", "deprecated": "false" },
+    "allowNullBody": { "kind": "parameter", "label": "producer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "false" },
+    "chmod": { "kind": "parameter", "label": "producer", "type": "string", "javaType": "java.lang.String", "deprecated": "false" },
+    "processStrategy": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.component.file.GenericFileProcessStrategy<T>", "deprecated": "false" },
+    "inProgressRepository": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.spi.IdempotentRepository<java.lang.String>", "deprecated": "false" },
+    "localWorkDirectory": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "java.lang.String", "deprecated": "false" },
+    "startingDirectoryMustExist": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "false" },
+    "directoryMustExist": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "false" },
+    "noop": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "false" },
+    "recursive": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "false" },
+    "delete": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "false" },
+    "maxMessagesPerPoll": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "int", "deprecated": "false" },
+    "eagerMaxMessagesPerPoll": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "true" },
+    "maxDepth": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "int", "deprecated": "false", "defaultValue": "2147483647" },
+    "minDepth": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "int", "deprecated": "false" },
+    "include": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "java.lang.String", "deprecated": "false" },
+    "exclude": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "java.lang.String", "deprecated": "false" },
+    "move": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.Expression", "deprecated": "false" },
+    "moveFailed": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.Expression", "deprecated": "false" },
+    "preMove": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.Expression", "deprecated": "false" },
+    "moveExisting": { "kind": "parameter", "label": "producer", "type": "object", "javaType": "org.apache.camel.Expression", "deprecated": "false" },
+    "idempotent": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": "false" },
+    "idempotentKey": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.Expression", "deprecated": "false" },
+    "idempotentRepository": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.spi.IdempotentRepository<java.lang.String>", "deprecated": "false" },
+    "filter": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.component.file.GenericFileFilter<T>", "deprecated": "false" },
+    "antInclude": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "java.lang.String", "deprecated": "false" },
+    "antExclude": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "java.lang.String", "deprecated": "false" },
+    "sorter": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "java.util.Comparator<org.apache.camel.component.file.GenericFile<T>>", "deprecated": "false" },
+    "sortBy": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "java.util.Comparator<org.apache.camel.Exchange>", "deprecated": "false" },
+    "readLock": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "java.lang.String", "enum": [ "none", "markerFile", "fileLock", "rename", "changed" ], "deprecated": "false" },
+    "readLockCheckInterval": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "long", "deprecated": "false", "defaultValue": "1000" },
+    "readLockTimeout": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "long", "deprecated": "false", "defaultValue": "10000" },
+    "readLockMarkerFile": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "true" },
+    "readLockLoggingLevel": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "DEBUG", "ERROR", "INFO", "TRACE", "WARN", "OFF" ], "deprecated": "false", "defaultValue": "WARN" },
+    "readLockMinLength": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "long", "deprecated": "false", "defaultValue": "1" },
+    "readLockMinAge": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "long", "deprecated": "false", "defaultValue": "0" },
+    "exclusiveReadLockStrategy": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.component.file.GenericFileExclusiveReadLockStrategy<T>", "deprecated": "false" },
+    "startScheduler": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "true" },
+    "initialDelay": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "long", "deprecated": "false", "defaultValue": "1000" },
+    "delay": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "long", "deprecated": "false", "defaultValue": "500" },
+    "timeUnit": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "java.util.concurrent.TimeUnit", "enum": [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ], "deprecated": "false", "defaultValue": "MILLISECONDS" },
+    "useFixedDelay": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "true" },
+    "pollStrategy": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": "false" },
+    "runLoggingLevel": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "DEBUG", "ERROR", "INFO", "TRACE", "WARN", "OFF" ], "deprecated": "false", "defaultValue": "TRACE" },
+    "sendEmptyMessageWhenIdle": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false" },
+    "greedy": { "kind": "parameter", "label": "consumer", "type": "boolean", "javaType": "boolean", "deprecated": "false" },
+    "scheduler": { "kind": "parameter", "label": "consumer", "type": "string", "javaType": "org.apache.camel.spi.ScheduledPollConsumerScheduler", "enum": [ "spring", "quartz2" ], "deprecated": "false" },
+    "schedulerProperties": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "java.util.Map<java.lang.String,java.lang.Object>", "deprecated": "false" },
+    "scheduledExecutorService": { "kind": "parameter", "label": "consumer", "type": "object", "javaType": "java.util.concurrent.ScheduledExecutorService", "deprecated": "false" },
+    "backoffMultiplier": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "int", "deprecated": "false" },
+    "backoffIdleThreshold": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "int", "deprecated": "false" },
+    "backoffErrorThreshold": { "kind": "parameter", "label": "consumer", "type": "integer", "javaType": "int", "deprecated": "false" },
+    "exchangePattern": { "kind": "parameter", "type": "string", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "RobustInOnly", "InOut", "InOptionalOut", "OutOnly", "RobustOutOnly", "OutIn", "OutOptionalIn" ], "deprecated": "false", "defaultValue": "InOnly", "description": "Sets the default exchange pattern when creating an exchange" },
+    "synchronous": { "kind": "parameter", "type": "boolean", "javaType": "boolean", "deprecated": "false", "defaultValue": "false", "description": "Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported)." }
+  }
+}
+