Repository: camel Updated Branches: refs/heads/master 7c6737bf5 -> 8f89b49dc
CAMEL-8211 - Camel commands - camel-component-info Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/8f89b49d Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/8f89b49d Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/8f89b49d Branch: refs/heads/master Commit: 8f89b49dcbcf15df702a788ed47e79ed5766831e Parents: 9df244d Author: lburgazzoli <lburgazz...@gmail.com> Authored: Wed Mar 2 13:23:40 2016 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Fri Mar 11 12:07:46 2016 +0100 ---------------------------------------------------------------------- .../camel/commands/AbstractCamelController.java | 54 ++++++ .../apache/camel/commands/CamelController.java | 9 + .../camel/commands/CatalogComponentHelper.java | 188 +++++++++++++++++++ .../commands/CatalogComponentInfoCommand.java | 142 ++++++++++++++ .../camel/commands/CatalogCommandTest.java | 22 +++ .../commands/catalog/CatalogComponentInfo.java | 45 +++++ .../blueprint/camel-commands-catalog.xml | 5 + 7 files changed, 465 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/8f89b49d/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 cea1b46..67b2746 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 @@ -29,6 +29,7 @@ import org.apache.camel.catalog.CatalogHelper; import org.apache.camel.catalog.DefaultCamelCatalog; import org.apache.camel.commands.internal.RegexUtil; import org.apache.camel.util.JsonSchemaHelper; +import org.apache.camel.util.ObjectHelper; /** * Abstract {@link org.apache.camel.commands.CamelController} that implementators should extend. @@ -102,6 +103,59 @@ public abstract class AbstractCamelController implements CamelController { return answer; } + protected Map<String, Object> loadProperties(String json, String group, Map<String, Object> answer) { + List<Map<String, String>> kv = JsonSchemaHelper.parseJsonSchema(group, json, true); + if (kv.isEmpty()) { + return answer; + } + + Map<String, Object> groupkv = new LinkedHashMap<>(); + answer.put(group, groupkv); + + for (Map<String, String> map : kv) { + boolean first = true; + Map<String, Object> properties = new LinkedHashMap<>(); + for (Map.Entry<String, String> entry : map.entrySet()) { + if (first) { + if (!ObjectHelper.equal(entry.getKey(), "name")) { + throw new IllegalStateException("First entry should be the property name"); + } + groupkv.put(entry.getValue(), properties); + first = false; + } else { + properties.put(entry.getKey(), entry.getValue()); + } + } + } + + return answer; + } + + @Override + public Map<String, Object> componentInfo(String filter) throws Exception { + Map<String, Object> answer = new LinkedHashMap<>(); + List<String> names = catalog.findComponentNames(); + for (String name : names) { + if (name.equalsIgnoreCase(filter)) { + String json = catalog.componentJSonSchema(name); + + List<Map<String, String>> kv; + + kv = JsonSchemaHelper.parseJsonSchema("component", json, false); + for (Map<String, String> map : kv) { + answer.putAll(map); + } + + loadProperties(json, "componentProperties", answer); + loadProperties(json, "properties", answer); + + break; + } + } + + return answer; + } + @Override public List<Map<String, String>> listComponentsCatalog(String filter) throws Exception { List<Map<String, String>> answer = new ArrayList<Map<String, String>>(); http://git-wip-us.apache.org/repos/asf/camel/blob/8f89b49d/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 b9fbcd1..65c2139 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 @@ -284,6 +284,15 @@ public interface CamelController { Map<String, Set<String>> listEipsLabelCatalog() throws Exception; /** + * Collects information about a Camel component from catalog + * + * @param name the component name + * @return a map of key/value pairs with component information + * @throws java.lang.Exception can be thrown + */ + Map<String, Object> componentInfo(String name) throws Exception; + + /** * Lists all components from the Camel components catalog * * @param filter optional filter to filter by labels http://git-wip-us.apache.org/repos/asf/camel/blob/8f89b49d/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentHelper.java ---------------------------------------------------------------------- diff --git a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentHelper.java b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentHelper.java new file mode 100644 index 0000000..d243539 --- /dev/null +++ b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentHelper.java @@ -0,0 +1,188 @@ +/** + * 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.commands; + +import java.io.PrintStream; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.camel.util.ObjectHelper; + +public final class CatalogComponentHelper { + private CatalogComponentHelper() { + } + + public static final class TableColumn { + private final String header; + private final String key; + private int maxLen; + private String formatString; + + public TableColumn(String header, String key) { + this.header = header; + this.key = key; + this.maxLen = header.length(); + this.formatString = null; + } + + public String getHeader() { + return header; + } + + public String getKey() { + return key; + } + + public int getMaxLen() { + return maxLen; + } + + public void computeMaxLen(Map<String, String> row) { + String val = row.get(key); + if (val != null) { + maxLen = Math.max(maxLen, val.length()); + } + } + + private String headerSeparator() { + StringBuilder sb = new StringBuilder(header.length()); + while (sb.length() < header.length()) { + sb.append('-'); + } + + return sb.toString(); + } + + private String formatString() { + if (formatString == null) { + formatString = new StringBuilder() + .append("%-").append(maxLen).append('.').append(maxLen).append('s') + .toString(); + } + + return formatString; + } + + public void printHeader(PrintStream out, boolean newLine) { + String outStr = String.format(formatString(), header); + + if (newLine) { + out.println(outStr.trim()); + } else { + out.print(outStr); + out.print(' '); + } + } + + public void printHeaderSeparator(PrintStream out, boolean newLine) { + String outStr = String.format(formatString(), headerSeparator()); + + if (newLine) { + out.println(outStr.trim()); + } else { + out.print(outStr); + out.print(' '); + } + } + + public void printValue(PrintStream out, Map<String, String> row, boolean newLine) { + String val = row.get(key); + if (val == null) { + val = ""; + } + + String outStr = String.format(formatString(), val); + + if (newLine) { + out.println(outStr.trim()); + } else { + out.print(outStr); + out.print(' '); + } + } + } + + public static final class Table { + private final List<TableColumn> columns; + private final List<Map<String, String>> rows; + + public Table(String[] headers, String[] keys) { + assert headers.length == keys.length; + + this.columns = new LinkedList<>(); + this.rows = new LinkedList<>(); + + for (int i = 0; i < headers.length; i++) { + columns.add(new TableColumn(headers[i], keys[i])); + } + } + + public boolean isEmpty() { + return rows.isEmpty(); + } + + public void addRow(String name, Map<String, Object> row) { + Map<String, String> rowData = null; + + for (TableColumn column : columns) { + Object val = row.get(column.getKey()); + if (ObjectHelper.isNotEmpty(val)) { + if (rowData == null) { + rowData = new LinkedHashMap<>(); + } + + rowData.put(column.getKey(), val.toString()); + } + } + + if (rowData != null) { + rowData.put("key", name); + rows.add(rowData); + + for (TableColumn column : columns) { + column.computeMaxLen(rowData); + } + } + } + + public void print(PrintStream out) { + for (int r = 0; r < rows.size(); r++) { + if (r == 0) { + printHeader(out); + } + + Map<String, String> row = rows.get(r); + for (int c = 0; c < columns.size(); c++) { + columns.get(c).printValue(out, row, c == columns.size() - 1); + } + } + } + + private void printHeader(PrintStream out) { + for (int c = 0; c < columns.size(); c++) { + TableColumn column = columns.get(c); + column.printHeader(out, c == columns.size() - 1); + } + for (int c = 0; c < columns.size(); c++) { + TableColumn column = columns.get(c); + column.printHeaderSeparator(out, c == columns.size() - 1); + } + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/8f89b49d/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentInfoCommand.java ---------------------------------------------------------------------- diff --git a/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentInfoCommand.java b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentInfoCommand.java new file mode 100644 index 0000000..b94d5b1 --- /dev/null +++ b/platforms/commands/commands-core/src/main/java/org/apache/camel/commands/CatalogComponentInfoCommand.java @@ -0,0 +1,142 @@ +/** + * 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.commands; + +import java.io.PrintStream; +import java.util.Map; +import java.util.regex.PatternSyntaxException; + +import org.apache.camel.catalog.CatalogHelper; +import org.apache.camel.commands.internal.RegexUtil; + +/** + * Shows properties of a component from Catalog + */ +public class CatalogComponentInfoCommand extends AbstractCamelCommand { + private static final String[][] COMPONENT_PROPERTIES = new String[][] { + {"Property", "Description"}, + {"key", "description"} + }; + + private static final String[][] COMPONENT_PROPERTIES_VERBOSE = new String[][] { + {"Property", "Description"}, + {"key", "description"} + }; + + private static final String[][] PROPERTIES = new String[][] { + {"Property", "Description"}, + {"key", "description"} + }; + + private static final String[][] PROPERTIES_VERBOSE = new String[][] { + {"Property", "Group", "Default Value", "Description"}, + {"key", "group", "defaultValue", "description"} + }; + + private final String name; + private final boolean verbose; + private final String labelFilter; + + public CatalogComponentInfoCommand(String name, boolean verbose, String labelFilter) { + this.name = name; + this.verbose = verbose; + this.labelFilter = labelFilter != null ? RegexUtil.wildcardAsRegex(labelFilter) : null; + } + + @Override + public Object execute(CamelController camelController, PrintStream out, PrintStream err) throws Exception { + final Map<String, Object> info = camelController.componentInfo(name); + + String component = name.toUpperCase(); + if (info.containsKey("description")) { + component += " :: " + info.get("description"); + } + + out.println(""); + out.println(component); + out.println(buildSeparatorString(component.length(), '-')); + out.println(""); + + + if (info.containsKey("label")) { + out.printf("label: %s\n", info.get("label")); + } + + if (info.containsKey("groupId") && info.containsKey("artifactId") && info.containsKey("version")) { + out.printf("maven: %s\n", info.get("groupId") + "/" + info.get("artifactId") + "/" + info.get("version")); + } + + dumpProperties("componentProperties", info, verbose ? COMPONENT_PROPERTIES_VERBOSE : COMPONENT_PROPERTIES, out); + dumpProperties("properties", info, verbose ? PROPERTIES_VERBOSE : PROPERTIES, out); + + return null; + } + + private void dumpProperties(String groupName, Map<String, Object> info, String[][] tableStruct, PrintStream out) { + Map<String, Object> group = (Map<String, Object>)info.get(groupName); + if (group != null) { + CatalogComponentHelper.Table table = new CatalogComponentHelper.Table(tableStruct[0], tableStruct[1]); + for (Map.Entry<String, Object> entry : group.entrySet()) { + if (entry.getValue() instanceof Map) { + Map<String, Object> data = (Map<String, Object>) entry.getValue(); + if (matchLabel(data)) { + table.addRow(entry.getKey(), data); + } + } + } + + if (!table.isEmpty()) { + out.println(""); + out.println(groupName); + out.println(""); + + table.print(out); + } + } + } + + private static String buildSeparatorString(int len, char pad) { + StringBuilder sb = new StringBuilder(len); + while (sb.length() < len) { + sb.append(pad); + } + + return sb.toString(); + } + + private boolean matchLabel(Map<String, Object> properties) { + if (labelFilter == null) { + return true; + } + + final String label = (String)properties.get("label"); + if (label != null) { + String[] parts = label.split(","); + for (String part : parts) { + try { + if (part.equalsIgnoreCase(labelFilter) || CatalogHelper.matchWildcard(part, labelFilter) || part.matches(labelFilter)) { + return true; + } + } catch (PatternSyntaxException e) { + // ignore as filter is maybe not a pattern + } + } + } + + return false; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/8f89b49d/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/CatalogCommandTest.java ---------------------------------------------------------------------- diff --git a/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/CatalogCommandTest.java b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/CatalogCommandTest.java index be4b941..4d03fb0 100644 --- a/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/CatalogCommandTest.java +++ b/platforms/commands/commands-core/src/test/java/org/apache/camel/commands/CatalogCommandTest.java @@ -54,4 +54,26 @@ public class CatalogCommandTest { context.stop(); } + + @Test + public void testComponentInfo() throws Exception { + CamelContext context = new DefaultCamelContext(); + context.setNameStrategy(new ExplicitCamelContextNameStrategy("foobar")); + context.start(); + + CamelController controller = new DummyCamelController(context); + + OutputStream os = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(os); + + CatalogComponentInfoCommand command = new CatalogComponentInfoCommand("hdfs", true, "consumer"); + command.execute(controller, ps, null); + + String out = os.toString(); + assertNotNull(out); + LOG.info("\n\n{}\n", out); + + context.stop(); + } + } http://git-wip-us.apache.org/repos/asf/camel/blob/8f89b49d/platforms/karaf/commands-catalog/src/main/java/org/apache/camel/karaf/commands/catalog/CatalogComponentInfo.java ---------------------------------------------------------------------- diff --git a/platforms/karaf/commands-catalog/src/main/java/org/apache/camel/karaf/commands/catalog/CatalogComponentInfo.java b/platforms/karaf/commands-catalog/src/main/java/org/apache/camel/karaf/commands/catalog/CatalogComponentInfo.java new file mode 100644 index 0000000..7ecae74 --- /dev/null +++ b/platforms/karaf/commands-catalog/src/main/java/org/apache/camel/karaf/commands/catalog/CatalogComponentInfo.java @@ -0,0 +1,45 @@ +/** + * 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.karaf.commands.catalog; + +import org.apache.camel.commands.CamelCommand; +import org.apache.camel.commands.CatalogComponentInfoCommand; +import org.apache.camel.karaf.commands.CamelCommandSupport; +import org.apache.felix.gogo.commands.Argument; +import org.apache.felix.gogo.commands.Command; +import org.apache.felix.gogo.commands.Option; + +@Command(scope = "camel", name = "catalog-component-info", description = "Show information about a Camel component from the Camel catalog") +public class CatalogComponentInfo extends CamelCommandSupport { + + @Argument(index = 0, name = "name", description = "The name of the Camel component.", + required = true, multiValued = false) + String name; + + @Option(name = "--verbose", aliases = "-v", description = "Verbose output which shows more information", + required = false, multiValued = false, valueToShowInHelp = "false") + boolean verbose; + + @Option(name = "--label", aliases = "-l", description = "To filter properties by their label(s), such as database", + required = false, multiValued = false) + String label; + + protected Object doExecute() throws Exception { + CamelCommand command = new CatalogComponentInfoCommand(name, verbose, label); + return command.execute(camelController, System.out, System.err); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/8f89b49d/platforms/karaf/commands-catalog/src/main/resources/OSGI-INF/blueprint/camel-commands-catalog.xml ---------------------------------------------------------------------- diff --git a/platforms/karaf/commands-catalog/src/main/resources/OSGI-INF/blueprint/camel-commands-catalog.xml b/platforms/karaf/commands-catalog/src/main/resources/OSGI-INF/blueprint/camel-commands-catalog.xml index eb002fc..bad7f72 100644 --- a/platforms/karaf/commands-catalog/src/main/resources/OSGI-INF/blueprint/camel-commands-catalog.xml +++ b/platforms/karaf/commands-catalog/src/main/resources/OSGI-INF/blueprint/camel-commands-catalog.xml @@ -24,6 +24,11 @@ <property name="camelController" ref="camelController"/> </action> </command> + <command name="camel-catalog/component-info"> + <action class="org.apache.camel.karaf.commands.catalog.CatalogComponentInfo"> + <property name="camelController" ref="camelController"/> + </action> + </command> <command name="camel-catalog/dataformat-list"> <action class="org.apache.camel.karaf.commands.catalog.CatalogDataFormatList"> <property name="camelController" ref="camelController"/>