CAMEL-7999: Add label to @UriEndpoint so we can group endpoints.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/1590a351 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/1590a351 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/1590a351 Branch: refs/heads/master Commit: 1590a3511e9c947770015298499d148f26686d63 Parents: 0dac21e Author: Claus Ibsen <davscl...@apache.org> Authored: Fri Nov 14 10:57:56 2014 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Fri Nov 14 13:02:05 2014 +0100 ---------------------------------------------------------------------- .../camel/catalog/CamelComponentCatalog.java | 5 ++ .../catalog/DefaultCamelComponentCatalog.java | 40 +++++++++ .../apache/camel/catalog/JSonSchemaHelper.java | 91 ++++++++++++++++++++ .../camel/commands/AbstractCamelController.java | 21 ++++- .../apache/camel/commands/CamelController.java | 3 +- .../commands/CatalogComponentListCommand.java | 53 +++++++----- .../catalog/CamelComponentCatalogTest.java | 43 +++++++++ .../karaf/commands/CatalogComponentList.java | 6 +- 8 files changed, 236 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/1590a351/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelComponentCatalog.java ---------------------------------------------------------------------- diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelComponentCatalog.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelComponentCatalog.java index 721ca51..766ff39 100644 --- a/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelComponentCatalog.java +++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/CamelComponentCatalog.java @@ -29,6 +29,11 @@ public interface CamelComponentCatalog { List<String> findComponentNames(); /** + * Find all the component names from the Camel catalog that matches the label + */ + List<String> findComponentNames(String label); + + /** * Returns the component information as JSon format. * * @param name the component name http://git-wip-us.apache.org/repos/asf/camel/blob/1590a351/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelComponentCatalog.java ---------------------------------------------------------------------- diff --git a/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelComponentCatalog.java b/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelComponentCatalog.java index 5d9902d..b5ee6dd 100644 --- a/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelComponentCatalog.java +++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/DefaultCamelComponentCatalog.java @@ -23,6 +23,8 @@ import java.io.InputStreamReader; import java.io.LineNumberReader; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.regex.PatternSyntaxException; /** * Default {@link org.apache.camel.catalog.CamelComponentCatalog}. @@ -48,6 +50,36 @@ public class DefaultCamelComponentCatalog implements CamelComponentCatalog { } @Override + public List<String> findComponentNames(String filter) { + List<String> answer = new ArrayList<String>(); + + List<String> names = findComponentNames(); + for (String name : names) { + String json = componentJSonSchema(name); + if (json != null) { + List<Map<String, String>> rows = JsonSchemaHelper.parseJsonSchema("component", json, false); + for (Map<String, String> row : rows) { + if (row.containsKey("label")) { + String label = row.get("label"); + String[] parts = label.split(","); + for (String part : parts) { + try { + if (part.equalsIgnoreCase(filter) || matchWildcard(part, filter) || part.matches(filter)) { + answer.add(name); + } + } catch (PatternSyntaxException e) { + // ignore as filter is maybe not a pattern + } + } + } + } + } + } + + return answer; + } + + @Override public String componentJSonSchema(String name) { String file = COMPONENTS_JSON + "/" + name + ".json"; @@ -118,4 +150,12 @@ public class DefaultCamelComponentCatalog implements CamelComponentCatalog { } } + 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; + } + return false; + } + } http://git-wip-us.apache.org/repos/asf/camel/blob/1590a351/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 new file mode 100644 index 0000000..b75f231 --- /dev/null +++ b/platforms/catalog/src/main/java/org/apache/camel/catalog/JSonSchemaHelper.java @@ -0,0 +1,91 @@ +/** + * 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.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class JsonSchemaHelper { + + private static final Pattern PATTERN = Pattern.compile("\"(.+?)\""); + + private JsonSchemaHelper() { + } + + /** + * Parses the json schema to split it into a list or rows, where each row contains key value pairs with the metadata + * + * @param group the group to parse from such as <tt>component</tt>, <tt>componentProperties</tt>, or <tt>properties</tt>. + * @param json the json + * @return a list of all the rows, where each row is a set of key value pairs with metadata + */ + public static List<Map<String, String>> parseJsonSchema(String group, String json, boolean parseProperties) { + List<Map<String, String>> answer = new ArrayList<Map<String, String>>(); + if (json == null) { + return answer; + } + + boolean found = false; + + // parse line by line + String[] lines = json.split("\n"); + for (String line : lines) { + // we need to find the group first + if (!found) { + String s = line.trim(); + found = s.startsWith("\"" + group + "\":"); + continue; + } + + // we should stop when we end the group + if (line.equals(" },") || line.equals(" }")) { + break; + } + + Map<String, String> row = new LinkedHashMap<String, String>(); + Matcher matcher = PATTERN.matcher(line); + + String key; + if (parseProperties) { + // when parsing properties the first key is given as name, so the first parsed token is the value of the name + key = "name"; + } else { + key = null; + } + while (matcher.find()) { + if (key == null) { + key = matcher.group(1); + } else { + String value = matcher.group(1); + row.put(key, value); + // reset + key = null; + } + } + if (!row.isEmpty()) { + answer.add(row); + } + } + + return answer; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/1590a351/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractCamelController.java ---------------------------------------------------------------------- diff --git a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractCamelController.java b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractCamelController.java index 56e69e6..f3965ae 100644 --- a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractCamelController.java +++ b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/AbstractCamelController.java @@ -30,6 +30,7 @@ import org.apache.camel.Endpoint; import org.apache.camel.Route; import org.apache.camel.catalog.CamelComponentCatalog; import org.apache.camel.catalog.DefaultCamelComponentCatalog; +import org.apache.camel.commands.internal.RegexUtil; import org.apache.camel.model.RouteDefinition; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.spi.RestRegistry; @@ -218,6 +219,7 @@ public abstract class AbstractCamelController implements CamelController { for (Map.Entry<String, Properties> entry : components.entrySet()) { String name = entry.getKey(); String description = null; + String label = null; // the status can be: // - loaded = in use // - classpath = on the classpath @@ -234,6 +236,8 @@ public abstract class AbstractCamelController implements CamelController { for (Map<String, String> row : rows) { if (row.containsKey("description")) { description = row.get("description"); + } else if (row.containsKey("label")) { + label = row.get("label"); } else if (row.containsKey("javaType")) { type = row.get("javaType"); } else if (row.containsKey("groupId")) { @@ -251,6 +255,9 @@ public abstract class AbstractCamelController implements CamelController { if (description != null) { row.put("description", description); } + if (label != null) { + row.put("label", label); + } if (type != null) { row.put("type", type); } @@ -271,16 +278,21 @@ public abstract class AbstractCamelController implements CamelController { } @Override - public List<Map<String, String>> listComponentsCatalog() throws Exception { + public List<Map<String, String>> listComponentsCatalog(String filter) throws Exception { List<Map<String, String>> answer = new ArrayList<Map<String, String>>(); - List<String> names = catalog.findComponentNames(); + if (filter != null) { + filter = RegexUtil.wildcardAsRegex(filter); + } + + List<String> names = filter != null ? catalog.findComponentNames(filter) : catalog.findComponentNames(); for (String name : names) { // load component json data, and parse it to gather the component meta-data String json = catalog.componentJSonSchema(name); List<Map<String, String>> rows = JsonSchemaHelper.parseJsonSchema("component", json, false); String description = null; + String label = null; // the status can be: // - loaded = in use // - classpath = on the classpath @@ -293,6 +305,8 @@ public abstract class AbstractCamelController implements CamelController { for (Map<String, String> row : rows) { if (row.containsKey("description")) { description = row.get("description"); + } else if (row.containsKey("label")) { + label = row.get("label"); } else if (row.containsKey("javaType")) { type = row.get("javaType"); } else if (row.containsKey("groupId")) { @@ -310,6 +324,9 @@ public abstract class AbstractCamelController implements CamelController { if (description != null) { row.put("description", description); } + if (label != null) { + row.put("label", label); + } if (type != null) { row.put("type", type); } http://git-wip-us.apache.org/repos/asf/camel/blob/1590a351/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java ---------------------------------------------------------------------- diff --git a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java index eb8f5a5..ad05893 100644 --- a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java +++ b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CamelController.java @@ -128,9 +128,10 @@ public interface CamelController { /** * Lists all components from the Camel components catalog * + * @param filter optional filter to filter by labels * @return a list of key/value pairs with component information * @throws java.lang.Exception is thrown if error loading resources to gather component information */ - List<Map<String, String>> listComponentsCatalog() throws Exception; + List<Map<String, String>> listComponentsCatalog(String filter) throws Exception; } http://git-wip-us.apache.org/repos/asf/camel/blob/1590a351/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentListCommand.java ---------------------------------------------------------------------- diff --git a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentListCommand.java b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentListCommand.java index a168045..62ce6fe 100644 --- a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentListCommand.java +++ b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentListCommand.java @@ -27,7 +27,7 @@ import java.util.Map; public class CatalogComponentListCommand extends AbstractCamelCommand { private static final String NAME_COLUMN_LABEL = "Name"; - private static final String STATUS_COLUMN_LABEL = "Status"; + private static final String LABEL_COLUMN_LABEL = "Label"; private static final String MAVEN_COLUMN_LABEL = "Maven Coordinate"; private static final String DESCRIPTION_COLUMN_LABEL = "Description"; @@ -42,14 +42,16 @@ public class CatalogComponentListCommand extends AbstractCamelCommand { private static final int MIN_COLUMN_WIDTH = 12; private boolean verbose; + private String label; - public CatalogComponentListCommand(boolean verbose) { + public CatalogComponentListCommand(boolean verbose, String label) { this.verbose = verbose; + this.label = label; } @Override public Object execute(CamelController camelController, PrintStream out, PrintStream err) throws Exception { - List<Map<String, String>> components = camelController.listComponentsCatalog(); + List<Map<String, String>> components = camelController.listComponentsCatalog(label); if (components == null || components.isEmpty()) { return null; @@ -60,26 +62,30 @@ public class CatalogComponentListCommand extends AbstractCamelCommand { final String rowFormat = buildFormatString(columnWidths, false, verbose); if (verbose) { - out.println(String.format(headerFormat, NAME_COLUMN_LABEL, STATUS_COLUMN_LABEL, MAVEN_COLUMN_LABEL, DESCRIPTION_COLUMN_LABEL)); - out.println(String.format(headerFormat, "----", "------", "----------------", "-----------")); + out.println(String.format(headerFormat, NAME_COLUMN_LABEL, LABEL_COLUMN_LABEL, MAVEN_COLUMN_LABEL, DESCRIPTION_COLUMN_LABEL)); + out.println(String.format(headerFormat, "----", "-----", "----------------", "-----------")); } else { - out.println(String.format(headerFormat, NAME_COLUMN_LABEL, DESCRIPTION_COLUMN_LABEL)); - out.println(String.format(headerFormat, "----", "-----------")); + out.println(String.format(headerFormat, NAME_COLUMN_LABEL, LABEL_COLUMN_LABEL, MAVEN_COLUMN_LABEL)); + out.println(String.format(headerFormat, "----", "-----", "----------------")); } for (final Map<String, String> component : components) { if (verbose) { String name = safeNull(component.get("name")); - String status = safeNull(component.get("status")); + String label = safeNull(component.get("label")); String maven = ""; if (component.containsKey("groupId") && component.containsKey("artifactId") && component.containsKey("version")) { maven = component.get("groupId") + "/" + component.get("artifactId") + "/" + component.get("version"); } String description = safeNull(component.get("description")); - out.println(String.format(rowFormat, name, status, maven, description)); + out.println(String.format(rowFormat, name, label, maven, description)); } else { String name = safeNull(component.get("name")); - String description = safeNull(component.get("description")); - out.println(String.format(rowFormat, name, description)); + String label = safeNull(component.get("label")); + String maven = ""; + if (component.containsKey("groupId") && component.containsKey("artifactId") && component.containsKey("version")) { + maven = component.get("groupId") + "/" + component.get("artifactId") + "/" + component.get("version"); + } + out.println(String.format(rowFormat, name, label, maven)); } } @@ -92,7 +98,7 @@ public class CatalogComponentListCommand extends AbstractCamelCommand { } else { // some of the options is optional so we need to start from 1 int maxNameLen = NAME_COLUMN_LABEL.length(); - int maxStatusLen = STATUS_COLUMN_LABEL.length(); + int maxLabelLen = LABEL_COLUMN_LABEL.length(); int maxMavenLen = MAVEN_COLUMN_LABEL.length(); int maxDescriptionLen = DESCRIPTION_COLUMN_LABEL.length(); @@ -103,9 +109,9 @@ public class CatalogComponentListCommand extends AbstractCamelCommand { if (name != null) { maxNameLen = Math.max(maxNameLen, name.length()); } - String status = component.get("status"); - if (status != null) { - maxStatusLen = Math.max(maxStatusLen, status.length()); + String label = component.get("label"); + if (label != null) { + maxLabelLen = Math.max(maxLabelLen, label.length()); } if (component.containsKey("groupId") && component.containsKey("artifactId") && component.containsKey("version")) { String mvn = component.get("groupId") + "/" + component.get("artifactId") + "/" + component.get("version"); @@ -119,7 +125,7 @@ public class CatalogComponentListCommand extends AbstractCamelCommand { final Map<String, Integer> retval = new Hashtable<String, Integer>(4); retval.put(NAME_COLUMN_LABEL, maxNameLen); - retval.put(STATUS_COLUMN_LABEL, maxStatusLen); + retval.put(LABEL_COLUMN_LABEL, maxLabelLen); retval.put(MAVEN_COLUMN_LABEL, maxMavenLen); retval.put(DESCRIPTION_COLUMN_LABEL, maxDescriptionLen); @@ -143,31 +149,34 @@ public class CatalogComponentListCommand extends AbstractCamelCommand { if (verbose) { int nameLen = Math.min(columnWidths.get(NAME_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); - int statusLen = Math.min(columnWidths.get(STATUS_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + int labelLen = Math.min(columnWidths.get(LABEL_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); int mavenLen = Math.min(columnWidths.get(MAVEN_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); int descriptionLen = Math.min(columnWidths.get(DESCRIPTION_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); nameLen = Math.max(MIN_COLUMN_WIDTH, nameLen); - statusLen = Math.max(MIN_COLUMN_WIDTH, statusLen); + labelLen = Math.max(MIN_COLUMN_WIDTH, labelLen); mavenLen = Math.max(MIN_COLUMN_WIDTH, mavenLen); descriptionLen = Math.max(MIN_COLUMN_WIDTH, descriptionLen); final StringBuilder retval = new StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH); retval.append(fieldPreamble).append("%-").append(nameLen).append('.').append(nameLen).append('s').append(fieldPostamble).append(' '); - retval.append(fieldPreamble).append("%-").append(statusLen).append('.').append(statusLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(labelLen).append('.').append(labelLen).append('s').append(fieldPostamble).append(' '); retval.append(fieldPreamble).append("%-").append(mavenLen).append('.').append(mavenLen).append('s').append(fieldPostamble).append(' '); retval.append(fieldPreamble).append("%-").append(descriptionLen).append('.').append(descriptionLen).append('s').append(fieldPostamble).append(' '); return retval.toString(); } else { int nameLen = Math.min(columnWidths.get(NAME_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); - int descriptionLen = Math.min(columnWidths.get(DESCRIPTION_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + int labelLen = Math.min(columnWidths.get(LABEL_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); + int mavenLen = Math.min(columnWidths.get(MAVEN_COLUMN_LABEL) + columnWidthIncrement, getMaxColumnWidth()); nameLen = Math.max(MIN_COLUMN_WIDTH, nameLen); - descriptionLen = Math.max(MIN_COLUMN_WIDTH, descriptionLen); + labelLen = Math.max(MIN_COLUMN_WIDTH, labelLen); + mavenLen = Math.max(MIN_COLUMN_WIDTH, mavenLen); final StringBuilder retval = new StringBuilder(DEFAULT_FORMAT_BUFFER_LENGTH); retval.append(fieldPreamble).append("%-").append(nameLen).append('.').append(nameLen).append('s').append(fieldPostamble).append(' '); - retval.append(fieldPreamble).append("%-").append(descriptionLen).append('.').append(descriptionLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(labelLen).append('.').append(labelLen).append('s').append(fieldPostamble).append(' '); + retval.append(fieldPreamble).append("%-").append(mavenLen).append('.').append(mavenLen).append('s').append(fieldPostamble).append(' '); return retval.toString(); } } http://git-wip-us.apache.org/repos/asf/camel/blob/1590a351/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/catalog/CamelComponentCatalogTest.java ---------------------------------------------------------------------- diff --git a/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/catalog/CamelComponentCatalogTest.java b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/catalog/CamelComponentCatalogTest.java index 67a991f..f9bb0db 100644 --- a/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/catalog/CamelComponentCatalogTest.java +++ b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/catalog/CamelComponentCatalogTest.java @@ -43,6 +43,49 @@ public class CamelComponentCatalogTest { } @Test + public void testFindComponentNamesFilter() { + CamelComponentCatalog catalog = new DefaultCamelComponentCatalog(); + List<String> names = catalog.findComponentNames("testing"); + + assertNotNull(names); + + LOG.info("Found {} names", names.size()); + assertTrue("Should find some testing components", names.size() > 0); + } + + @Test + public void testFindComponentNamesFilterWildcard() { + CamelComponentCatalog catalog = new DefaultCamelComponentCatalog(); + List<String> names = catalog.findComponentNames("t*"); + + assertNotNull(names); + + LOG.info("Found {} names", names.size()); + assertTrue("Should find some t* components", names.size() > 0); + } + + @Test + public void testFindComponentNamesFilterTwo() { + CamelComponentCatalog catalog = new DefaultCamelComponentCatalog(); + List<String> names = catalog.findComponentNames("transformation"); + + assertNotNull(names); + + LOG.info("Found {} names", names.size()); + assertTrue("Should find some transformation components", names.size() > 0); + } + + @Test + public void testFindComponentNamesFilterNoMatch() { + CamelComponentCatalog catalog = new DefaultCamelComponentCatalog(); + List<String> names = catalog.findComponentNames("cannotmatchme"); + + assertNotNull(names); + + assertTrue("Should not match any components", names.size() == 0); + } + + @Test public void testCoreComponentJson() { CamelComponentCatalog catalog = new DefaultCamelComponentCatalog(); String json = catalog.componentJSonSchema("bean"); http://git-wip-us.apache.org/repos/asf/camel/blob/1590a351/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CatalogComponentList.java ---------------------------------------------------------------------- diff --git a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CatalogComponentList.java b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CatalogComponentList.java index 2fc2463..05c4e1a 100644 --- a/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CatalogComponentList.java +++ b/platforms/karaf/commands/src/main/java/org/apache/camel/karaf/commands/CatalogComponentList.java @@ -27,8 +27,12 @@ public class CatalogComponentList extends CamelCommandSupport { required = false, multiValued = false, valueToShowInHelp = "false") boolean verbose; + @Option(name = "--label", aliases = "-l", description = "To filter components by their label(s), such as database", + required = false, multiValued = false) + String label; + protected Object doExecute() throws Exception { - CatalogComponentListCommand command = new CatalogComponentListCommand(verbose); + CatalogComponentListCommand command = new CatalogComponentListCommand(verbose, label); return command.execute(camelController, System.out, System.err); }