Updated Branches: refs/heads/master ca35a4d7b -> 4cc51e1c6
provide an implementation of CAMEL-6391 so that we can use completion when entering the endpoint path values. for example for file components, we can use bash style completion on the available directory/file names from a karaf command, CLI tool, IDE or web based tool Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/4cc51e1c Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/4cc51e1c Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/4cc51e1c Branch: refs/heads/master Commit: 4cc51e1c6ed20787cf98888241e2909e72d05331 Parents: ca35a4d Author: James Strachan <james.strac...@gmail.com> Authored: Fri May 24 10:23:13 2013 +0100 Committer: James Strachan <james.strac...@gmail.com> Committed: Fri May 24 10:23:13 2013 +0100 ---------------------------------------------------------------------- .../org/apache/camel/ComponentConfiguration.java | 15 +++ .../management/mbean/ManagedCamelContextMBean.java | 22 ++++ .../apache/camel/component/file/FileComponent.java | 56 ++++++++++- .../camel/impl/ComponentConfigurationSupport.java | 9 ++ .../management/mbean/ManagedCamelContext.java | 19 ++++ .../org/apache/camel/spi/EndpointCompleter.java | 41 ++++++++ .../camel/management/EndpointCompletionTest.java | 78 +++++++++++++++ 7 files changed, 239 insertions(+), 1 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/4cc51e1c/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java b/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java index 91ac7cf..4873ad4 100644 --- a/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java +++ b/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java @@ -17,6 +17,7 @@ package org.apache.camel; import java.net.URISyntaxException; +import java.util.List; import java.util.Map; import java.util.SortedMap; @@ -134,5 +135,19 @@ public interface ComponentConfiguration { */ void setEndpointParameter(Endpoint endpoint, String name, Object value) throws RuntimeCamelException; + /** + * A helper method for tools such as CLIs, IDEs or web tools that provides a completion list for Endpoint Paths + * rather like bash tab completion or Karaf attribute or option completion handers. + * + * So given the current configuration data, return a list of completions given the specified text. + * + * e.g. return the files in a directory, the matching queues in a message broker, the database tables in a database component etc + * + * @param completionText the prefix text used to complete on (usually a matching bit of text) + * + * @return a list of matches + * @return a list of matches + */ + List<String> completeEndpointPath(String completionText); } http://git-wip-us.apache.org/repos/asf/camel/blob/4cc51e1c/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java index 002f556..ea4e8b9 100644 --- a/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java +++ b/camel-core/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java @@ -16,6 +16,7 @@ */ package org.apache.camel.api.management.mbean; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -172,6 +173,15 @@ public interface ManagedCamelContextMBean extends ManagedPerformanceCounterMBean Map<String, Properties> findComponents() throws Exception; /** + * Find the names of all the Camel components available in the classpath and {@link org.apache.camel.spi.Registry}. + * + * @return a list with the names of the camel components + * @throws Exception is thrown if error occurred + */ + @ManagedOperation(description = "Find all Camel components names available in the classpath") + List<String> findComponentNames() throws Exception; + + /** * Resets all the performance counters. * * @param includeRoutes whether to reset all routes as well. @@ -180,4 +190,16 @@ public interface ManagedCamelContextMBean extends ManagedPerformanceCounterMBean @ManagedOperation(description = "Reset counters") void reset(boolean includeRoutes) throws Exception; + + /** + * Helper method for tooling which returns the completion list of the endpoint path + * from the given endpoint name, properties and current path expression. + * + * For example if using the file endpoint, this should complete a list of files (rather like bash completion) + * or for an ActiveMQ component this should complete the list of queues or topics. + * + */ + @ManagedOperation(description = "Returns the list of available endpoint paths for the given component name, endpoint properties and completion text") + List<String> completeEndpointPath(String componentName, Map<String,Object> endpointParameters, String completionText) throws Exception; + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/4cc51e1c/camel-core/src/main/java/org/apache/camel/component/file/FileComponent.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/file/FileComponent.java b/camel-core/src/main/java/org/apache/camel/component/file/FileComponent.java index 8db964a..8ec22df 100644 --- a/camel-core/src/main/java/org/apache/camel/component/file/FileComponent.java +++ b/camel-core/src/main/java/org/apache/camel/component/file/FileComponent.java @@ -17,15 +17,20 @@ package org.apache.camel.component.file; import java.io.File; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import org.apache.camel.ComponentConfiguration; +import org.apache.camel.spi.EndpointCompleter; import org.apache.camel.util.FileUtil; +import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.StringHelper; /** * File component. */ -public class FileComponent extends GenericFileComponent<File> { +public class FileComponent extends GenericFileComponent<File> implements EndpointCompleter { /** * GenericFile property on Camel Exchanges. @@ -60,4 +65,53 @@ public class FileComponent extends GenericFileComponent<File> { protected void afterPropertiesSet(GenericFileEndpoint<File> endpoint) throws Exception { // noop } + + public List<String> completeEndpointPath(ComponentConfiguration configuration, String completionText) { + boolean empty = ObjectHelper.isEmpty(completionText); + String pattern = completionText; + File file = new File(completionText); + String prefix = completionText; + if (file.exists()) { + pattern = ""; + } else { + String startPath = "."; + if (!empty) { + int idx = completionText.lastIndexOf('/'); + if (idx >= 0) { + startPath = completionText.substring(0, idx); + if (startPath.length() == 0) { + startPath = "/"; + } + pattern = completionText.substring(idx + 1); + } + } + file = new File(startPath); + prefix = startPath; + } + if (prefix.length() > 0 && !prefix.endsWith("/")) { + prefix += "/"; + } + if (prefix.equals("./")) { + prefix = ""; + } + File[] list = file.listFiles(); + List<String> answer = new ArrayList<String>(); + for (File aFile : list) { + String name = aFile.getName(); + if (pattern.length() == 0 || name.contains(pattern)) { + if (isValidEndpointCompletion(configuration, completionText, aFile)) { + answer.add(prefix + name); + } + } + } + return answer; + } + + /** + * Returns true if this is a valid file for completion. By default we should ignore files that start with a "." + */ + protected boolean isValidEndpointCompletion(ComponentConfiguration configuration, String completionText, + File file) { + return !file.getName().startsWith("."); + } } http://git-wip-us.apache.org/repos/asf/camel/blob/4cc51e1c/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java b/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java index c529148..027a610 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java +++ b/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java @@ -27,6 +27,7 @@ import java.util.Set; import org.apache.camel.Component; import org.apache.camel.ComponentConfiguration; import org.apache.camel.Endpoint; +import org.apache.camel.spi.EndpointCompleter; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.URISupport; import org.apache.camel.util.UnsafeUriCharactersEncoder; @@ -154,6 +155,14 @@ public abstract class ComponentConfigurationSupport implements ComponentConfigur return getParameterConfigurationMap().get(name); } + public List<String> completeEndpointPath(String completionText) { + if (component instanceof EndpointCompleter) { + EndpointCompleter completer = (EndpointCompleter) component; + return completer.completeEndpointPath(this, completionText); + } + return new ArrayList<String>(); + } + /** * Allow implementations to validate whether a property name is valid * and either throw an exception or log a warning of an unknown property being used http://git-wip-us.apache.org/repos/asf/camel/blob/4cc51e1c/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java index 4d58660..cc6c10e 100644 --- a/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java +++ b/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java @@ -17,6 +17,7 @@ package org.apache.camel.management.mbean; import java.io.InputStream; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; @@ -29,6 +30,8 @@ import javax.management.MBeanServerInvocationHandler; import javax.management.ObjectName; import org.apache.camel.CamelContext; +import org.apache.camel.Component; +import org.apache.camel.ComponentConfiguration; import org.apache.camel.Endpoint; import org.apache.camel.ManagementStatisticsLevel; import org.apache.camel.ProducerTemplate; @@ -336,6 +339,22 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti return CamelContextHelper.findComponents(context); } + public List<String> findComponentNames() throws Exception { + Map<String, Properties> map = findComponents(); + return new ArrayList<String>(map.keySet()); + } + + public List<String> completeEndpointPath(String componentName, Map<String, Object> endpointParameters, + String completionText) throws Exception { + if (completionText == null) { + completionText = ""; + } + Component component = context.getComponent(componentName); + ComponentConfiguration configuration = component.createComponentConfiguration(); + configuration.setParameters(endpointParameters); + return configuration.completeEndpointPath(completionText); + } + public void reset(boolean includeRoutes) throws Exception { reset(); http://git-wip-us.apache.org/repos/asf/camel/blob/4cc51e1c/camel-core/src/main/java/org/apache/camel/spi/EndpointCompleter.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/spi/EndpointCompleter.java b/camel-core/src/main/java/org/apache/camel/spi/EndpointCompleter.java new file mode 100644 index 0000000..2fd34ec --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/spi/EndpointCompleter.java @@ -0,0 +1,41 @@ +/** + * + * 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.spi; + +import java.util.List; + +import org.apache.camel.ComponentConfiguration; + +/** + * A helper interface used by the {@link org.apache.camel.ComponentConfiguration#completeEndpointPath(String)} method + * to allow endpoint paths to be completed. + * + * {@link org.apache.camel.Component} implementations should try to implement this API to make your component + * behave nicer in command line, IDE and web based tools. + */ +public interface EndpointCompleter { + /** + * Given the configuration and completion text, return a list of possible completion values + * for a command line, IDE or web based tool. + * + * @returns the list of completion values if any (rather like bash completion, prefix values can be returned + * - such as just the directories in the current path rather than returning every possible file name on a disk). + */ + List<String> completeEndpointPath(ComponentConfiguration configuration, + String completionText); +} http://git-wip-us.apache.org/repos/asf/camel/blob/4cc51e1c/camel-core/src/test/java/org/apache/camel/management/EndpointCompletionTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/management/EndpointCompletionTest.java b/camel-core/src/test/java/org/apache/camel/management/EndpointCompletionTest.java new file mode 100644 index 0000000..fff57b8 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/management/EndpointCompletionTest.java @@ -0,0 +1,78 @@ +/** + * 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.management; + +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.ReflectionException; + +import com.sun.javafx.tools.packager.Log; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EndpointCompletionTest extends ManagementTestSupport { + private static final transient Logger LOG = LoggerFactory.getLogger(EndpointCompletionTest.class); + + @SuppressWarnings("unchecked") + public void testEndpointCompletion() throws Exception { + MBeanServer mbeanServer = getMBeanServer(); + ObjectName on = ObjectName.getInstance("org.apache.camel:context=localhost/camel-1,type=context,name=\"camel-1\""); + assertNotNull(on); + mbeanServer.isRegistered(on); + + String componentName = "file"; + HashMap<String, Object> properties = new HashMap<String, Object>(); + List<String> completions = assertCompletion(mbeanServer, on, componentName, properties, ""); + completions = assertCompletion(mbeanServer, on, componentName, properties, "po"); + completions = assertCompletion(mbeanServer, on, componentName, properties, "/"); + completions = assertCompletion(mbeanServer, on, componentName, properties, "/usr/local"); + completions = assertCompletion(mbeanServer, on, componentName, properties, "/usr/local/"); + completions = assertCompletion(mbeanServer, on, componentName, properties, "/usr/local/b"); + + } + + private List<String> assertCompletion(MBeanServer mbeanServer, ObjectName on, String componentName, + HashMap<String, Object> properties, String completionText) + throws InstanceNotFoundException, MBeanException, ReflectionException { + Object[] params = {componentName, properties, completionText}; + String[] signature = { "java.lang.String", "java.util.Map", "java.lang.String" }; + + List completions = assertIsInstanceOf(List.class, + mbeanServer.invoke(on, "completeEndpointPath", params, signature)); + + LOG.info("Component " + componentName + " with '" + completionText + "' Returned: " + completions); + return completions; + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + } + }; + } + +}