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 {
+            }
+        };
+    }
+
+}

Reply via email to