Camel catalog - Add api to validate endpoint uri
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/3e109750 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/3e109750 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/3e109750 Branch: refs/heads/master Commit: 3e1097502bb06043b480969641a14f50a35f0259 Parents: 6a4534d Author: Claus Ibsen <davscl...@apache.org> Authored: Sat Dec 19 14:49:43 2015 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Sun Dec 20 07:05:47 2015 +0100 ---------------------------------------------------------------------- .../org/apache/camel/catalog/CamelCatalog.java | 11 ++ .../camel/catalog/DefaultCamelCatalog.java | 117 +++++++++++++++++++ .../apache/camel/catalog/JSonSchemaHelper.java | 78 +++++++++++++ .../apache/camel/catalog/CamelCatalogTest.java | 45 ++++++- 4 files changed, 250 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/3e109750/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 7dc67a0..dc1a3ca 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 @@ -170,6 +170,17 @@ public interface CamelCatalog { Map<String, String> endpointProperties(String uri) throws URISyntaxException; /** + * Parses and validates the endpoint uri and constructs a key/value properties of each option + * + * @param uri the endpoint uri + * @return invalid properties as key/value properties of each invalid option, returns an empty map if no validation errors + */ + Map<String, String> validateProperties(String uri) throws URISyntaxException; + + // TODO: json with error instead of map + // with description of the error, index, etc + + /** * Returns the component name from the given endpoint uri * * @param uri the endpoint uri http://git-wip-us.apache.org/repos/asf/camel/blob/3e109750/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 870bc0f..13b3052 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 @@ -42,8 +42,14 @@ import org.w3c.dom.Document; import static org.apache.camel.catalog.CatalogHelper.after; import static org.apache.camel.catalog.JSonSchemaHelper.getPropertyDefaultValue; +import static org.apache.camel.catalog.JSonSchemaHelper.getPropertyEnum; +import static org.apache.camel.catalog.JSonSchemaHelper.getRow; +import static org.apache.camel.catalog.JSonSchemaHelper.isPropertyBoolean; +import static org.apache.camel.catalog.JSonSchemaHelper.isPropertyInteger; +import static org.apache.camel.catalog.JSonSchemaHelper.isPropertyNumber; import static org.apache.camel.catalog.JSonSchemaHelper.isPropertyRequired; import static org.apache.camel.catalog.URISupport.createQueryString; +import static org.apache.camel.catalog.URISupport.isEmpty; import static org.apache.camel.catalog.URISupport.normalizeUri; import static org.apache.camel.catalog.URISupport.stripQuery; @@ -72,9 +78,17 @@ public class DefaultCamelCatalog implements CamelCatalog { private boolean caching; + /** + * Creates the {@link CamelCatalog} without caching enabled. + */ public DefaultCamelCatalog() { } + /** + * Creates the {@link CamelCatalog} + * + * @param caching whether to use cache + */ public DefaultCamelCatalog(boolean caching) { this.caching = caching; } @@ -632,6 +646,109 @@ public class DefaultCamelCatalog implements CamelCatalog { } @Override + public Map<String, String> validateProperties(String uri) throws URISyntaxException { + Map<String, String> answer = new LinkedHashMap<String, String>(); + + // parse the uri + URI u = normalizeUri(uri); + String scheme = u.getScheme(); + String json = componentJSonSchema(scheme); + List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("properties", json, true); + + // parse into a map of properties of the uri, and look for options that are invalid + Map<String, String> properties = endpointProperties(uri); + for (Map.Entry<String, String> property : properties.entrySet()) { + String name = property.getKey(); + String value = property.getValue(); + boolean placeholder = value.startsWith("{{") || value.startsWith("${") || value.startsWith("$simple{"); + + Map<String, String> row = getRow(rows, name); + // unknown option + if (row == null) { + answer.put(name, property.getValue()); + } else { + // invalid value/type + + // is required but the value is empty + boolean required = isPropertyRequired(rows, name); + if (required && isEmpty(value)) { + answer.put(name, value); + } + + // is enum but the value is not within the enum range + // but we can only check if the value is not a placeholder + String enums = getPropertyEnum(rows, name); + if (!placeholder && enums != null) { + boolean found = false; + for (String s : enums.split(",")) { + if (value.equalsIgnoreCase(s)) { + found = true; + break; + } + } + if (!found) { + answer.put(name, value); + } + } + + // is boolean + if (!placeholder && isPropertyBoolean(rows, name)) { + // value must be a boolean + boolean bool = "true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value); + if (!bool) { + answer.put(name, value); + } + } + + // is integer + if (!placeholder && isPropertyInteger(rows, name)) { + // value must be an integer + boolean valid = false; + try { + valid = Integer.valueOf(value) != null; + } catch (Exception e) { + // ignore + } + if (!valid) { + answer.put(name, value); + } + } + + // is number + if (!placeholder && isPropertyNumber(rows, name)) { + // value must be an number + boolean valid = false; + try { + valid = Double.valueOf(value).isNaN() == false || Float.valueOf(value).isNaN() == false; + } catch (Exception e) { + // ignore + } + if (!valid) { + answer.put(name, value); + } + } + } + } + + // now check if all required values are there, and that a default value does not exists + for (Map<String, String> row : rows) { + String name = row.get("name"); + boolean required = isPropertyRequired(rows, name); + if (required) { + String value = properties.get(name); + if (isEmpty(value)) { + value = getPropertyDefaultValue(rows, name); + } + if (isEmpty(value)) { + answer.put(name, value); + } + } + } + + return answer; + } + + @Override public Map<String, String> endpointProperties(String uri) throws URISyntaxException { // NOTICE: This logic is similar to org.apache.camel.util.EndpointHelper#endpointProperties // as the catalog also offers similar functionality (without having camel-core on classpath) http://git-wip-us.apache.org/repos/asf/camel/blob/3e109750/platforms/catalog/src/main/java/org/apache/camel/catalog/JSonSchemaHelper.java ---------------------------------------------------------------------- diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/JSonSchemaHelper.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/JSonSchemaHelper.java index 17e0f85..e3e4beb 100644 --- a/platforms/catalog/src/main/java/org/apache/camel/catalog/JSonSchemaHelper.java +++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/JSonSchemaHelper.java @@ -129,6 +129,57 @@ public final class JSonSchemaHelper { return false; } + public static boolean isPropertyBoolean(List<Map<String, String>> rows, String name) { + for (Map<String, String> row : rows) { + String type = null; + boolean found = false; + if (row.containsKey("name")) { + found = name.equals(row.get("name")); + } + if (row.containsKey("type")) { + type = row.get("type"); + } + if (found) { + return "boolean".equals(type); + } + } + return false; + } + + public static boolean isPropertyInteger(List<Map<String, String>> rows, String name) { + for (Map<String, String> row : rows) { + String type = null; + boolean found = false; + if (row.containsKey("name")) { + found = name.equals(row.get("name")); + } + if (row.containsKey("type")) { + type = row.get("type"); + } + if (found) { + return "integer".equals(type); + } + } + return false; + } + + public static boolean isPropertyNumber(List<Map<String, String>> rows, String name) { + for (Map<String, String> row : rows) { + String type = null; + boolean found = false; + if (row.containsKey("name")) { + found = name.equals(row.get("name")); + } + if (row.containsKey("type")) { + type = row.get("type"); + } + if (found) { + return "number".equals(type); + } + } + return false; + } + public static String getPropertyDefaultValue(List<Map<String, String>> rows, String name) { for (Map<String, String> row : rows) { String defaultValue = null; @@ -146,4 +197,31 @@ public final class JSonSchemaHelper { return null; } + public static String getPropertyEnum(List<Map<String, String>> rows, String name) { + for (Map<String, String> row : rows) { + String enums = null; + String defaultValue = null; + boolean found = false; + if (row.containsKey("name")) { + found = name.equals(row.get("name")); + } + if (row.containsKey("enum")) { + enums = row.get("enum"); + } + if (found) { + return enums; + } + } + return null; + } + + public static Map<String, String> getRow(List<Map<String, String>> rows, String key) { + for (Map<String, String> row : rows) { + if (key.equals(row.get("name"))) { + return row; + } + } + return null; + } + } http://git-wip-us.apache.org/repos/asf/camel/blob/3e109750/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 324362f..4c020da 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 @@ -22,7 +22,6 @@ import java.util.Map; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -388,6 +387,50 @@ public class CamelCatalogTest { } @Test + public void validateProperties() throws Exception { + // valid + Map<String, String> map = catalog.validateProperties("log:mylog"); + assertNotNull(map); + assertEquals(0, map.size()); + + // unknown + map = catalog.validateProperties("log:mylog?level=WARN&foo=bar"); + assertNotNull(map); + assertEquals(1, map.size()); + assertEquals("bar", map.get("foo")); + + // enum + map = catalog.validateProperties("jms:unknown:myqueue"); + assertNotNull(map); + assertEquals(1, map.size()); + + // okay + map = catalog.validateProperties("yammer:MESSAGES?accessToken=aaa&consumerKey=bbb&consumerSecret=ccc&useJson=true&initialDelay=500"); + assertNotNull(map); + assertEquals(0, map.size()); + + // required / boolean / integer + map = catalog.validateProperties("yammer:MESSAGES?accessToken=aaa&consumerKey=&useJson=no&initialDelay=five"); + assertNotNull(map); + assertEquals(4, map.size()); + assertEquals(null, map.get("consumerKey")); + assertEquals(null, map.get("consumerSecret")); + assertEquals("no", map.get("useJson")); + assertEquals("five", map.get("initialDelay")); + + // okay + map = catalog.validateProperties("mqtt:myqtt?reconnectBackOffMultiplier=2.5"); + assertNotNull(map); + assertEquals(0, map.size()); + + // number + map = catalog.validateProperties("mqtt:myqtt?reconnectBackOffMultiplier=five"); + assertNotNull(map); + assertEquals(1, map.size()); + assertEquals("five", map.get("reconnectBackOffMultiplier")); + } + + @Test public void testEndpointComponentName() throws Exception { String name = catalog.endpointComponentName("jms:queue:foo"); assertEquals("jms", name);