This is an automated email from the ASF dual-hosted git repository.

nfilotto pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karaf.git


The following commit(s) were added to refs/heads/main by this push:
     new 6ae6d013 GH-264: Add camel:* shell commands (#282)
6ae6d013 is described below

commit 6ae6d013abb24fb2b7ba131433a18de56bcbf857
Author: JB Onofré <[email protected]>
AuthorDate: Wed May 15 12:02:49 2024 +0200

    GH-264: Add camel:* shell commands (#282)
---
 .../core/AbstractOsgiDefaultCamelContext.java      |   1 -
 features/src/main/feature/camel-features.xml       |   5 +-
 pom.xml                                            |   9 +-
 shell/pom.xml                                      |  86 +++++++++++++++
 .../camel/karaf/shell/CamelCommandSupport.java     |  74 +++++++++++++
 .../apache/camel/karaf/shell/ContextInflight.java  |  94 ++++++++++++++++
 .../org/apache/camel/karaf/shell/ContextList.java  |  66 +++++++++++
 .../apache/camel/karaf/shell/ContextResume.java    |  48 ++++++++
 .../org/apache/camel/karaf/shell/ContextStart.java |  54 +++++++++
 .../org/apache/camel/karaf/shell/ContextStop.java  |  49 +++++++++
 .../apache/camel/karaf/shell/ContextSuspend.java   |  49 +++++++++
 .../org/apache/camel/karaf/shell/EndpointList.java |  95 ++++++++++++++++
 .../apache/camel/karaf/shell/EndpointStats.java    | 122 +++++++++++++++++++++
 .../org/apache/camel/karaf/shell/RestApiDoc.java   |  53 +++++++++
 .../apache/camel/karaf/shell/RestRegistryList.java |  87 +++++++++++++++
 .../org/apache/camel/karaf/shell/RouteList.java    |  91 +++++++++++++++
 .../apache/camel/karaf/shell/RouteResetStats.java  |  67 +++++++++++
 .../org/apache/camel/karaf/shell/RouteResume.java  |  53 +++++++++
 .../org/apache/camel/karaf/shell/RouteStart.java   |  53 +++++++++
 .../org/apache/camel/karaf/shell/RouteStop.java    |  53 +++++++++
 .../org/apache/camel/karaf/shell/RouteSuspend.java |  53 +++++++++
 .../shell/completers/CamelContextCompleter.java    |  47 ++++++++
 .../karaf/shell/completers/RouteCompleter.java     |  55 ++++++++++
 23 files changed, 1358 insertions(+), 6 deletions(-)

diff --git 
a/core/camel-core-osgi/src/main/java/org/apache/camel/karaf/core/AbstractOsgiDefaultCamelContext.java
 
b/core/camel-core-osgi/src/main/java/org/apache/camel/karaf/core/AbstractOsgiDefaultCamelContext.java
index b073b9ff..91a3169b 100644
--- 
a/core/camel-core-osgi/src/main/java/org/apache/camel/karaf/core/AbstractOsgiDefaultCamelContext.java
+++ 
b/core/camel-core-osgi/src/main/java/org/apache/camel/karaf/core/AbstractOsgiDefaultCamelContext.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.camel.karaf.core;
 
 import org.apache.camel.impl.DefaultCamelContext;
diff --git a/features/src/main/feature/camel-features.xml 
b/features/src/main/feature/camel-features.xml
index 9021aedb..9e1ee157 100644
--- a/features/src/main/feature/camel-features.xml
+++ b/features/src/main/feature/camel-features.xml
@@ -251,13 +251,10 @@
         
<bundle>mvn:org.apache.camel.karaf/camel-xslt/${project.version}</bundle>
         
<bundle>mvn:org.apache.camel.karaf/camel-directvm/${project.version}</bundle>
         <bundle>mvn:org.apache.camel.karaf/camel-vm/${project.version}</bundle>
-        <!--
         <conditional>
             <condition>shell</condition>
-            
<bundle>mvn:org.apache.camel.karaf/camel-commands-core/${project.version}</bundle>
-            
<bundle>mvn:org.apache.camel.karaf/camel-karaf-commands/${project.version}</bundle>
+            
<bundle>mvn:org.apache.camel.karaf/camel-karaf-shell/${project.version}</bundle>
         </conditional>
-        -->
         <!-- allow camel to access its own mbeans for karaf commands and other 
needs -->
         <config name="jmx.acl.org.apache.camel">
             * = *
diff --git a/pom.xml b/pom.xml
index 077a20da..3bcde132 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,7 +64,7 @@
 
     <modules>
         <module>core</module>
-        <!-- <module>shell</module> -->
+        <module>shell</module>
         <module>components</module>
         <module>features</module>
         <!-- <module>archetypes</module> -->
@@ -566,6 +566,7 @@
         <velocity-version>2.3</velocity-version>
         <bouncycastle-version>1.77</bouncycastle-version>
     </properties>
+
     <dependencyManagement>
         <dependencies>
             <dependency>
@@ -593,6 +594,11 @@
                 <artifactId>org.osgi.service.component.annotations</artifactId>
                 <version>${osgi.service.component.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.karaf.shell</groupId>
+                <artifactId>org.apache.karaf.shell.core</artifactId>
+                <version>${karaf.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.aries.blueprint</groupId>
                 <artifactId>org.apache.aries.blueprint.core</artifactId>
@@ -653,6 +659,7 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <version>${maven-bundle-plugin-version}</version>
                 <extensions>true</extensions>
+                <inherited>true</inherited>
                 <configuration>
                     <instructions>
                         
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
diff --git a/shell/pom.xml b/shell/pom.xml
new file mode 100644
index 00000000..50172e4b
--- /dev/null
+++ b/shell/pom.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.karaf</groupId>
+        <artifactId>camel-karaf</artifactId>
+        <version>4.5.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-karaf-shell</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Camel :: Karaf :: Shell Commands</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core</artifactId>
+            <version>${camel.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-services-maven-plugin</artifactId>
+                <version>${karaf.version}</version>
+                <executions>
+                    <execution>
+                        <id>service-metadata-generate</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>service-metadata-generate</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Private-Package>
+                            org.apache.camel.karaf.shell,
+                            org.apache.camel.karaf.shell.completers
+                        </Private-Package>
+                        <Import-Package>
+                            org.apache.karaf.shell*;version="[4,5)",
+                            *
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git 
a/shell/src/main/java/org/apache/camel/karaf/shell/CamelCommandSupport.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/CamelCommandSupport.java
new file mode 100644
index 00000000..b4550206
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/CamelCommandSupport.java
@@ -0,0 +1,74 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+public abstract class CamelCommandSupport {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(CamelCommandSupport.class);
+
+    @Reference
+    private BundleContext bundleContext;
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public List<CamelContext> getCamelContexts()  {
+        List<CamelContext> camelContexts = new ArrayList<>();
+
+        try {
+            ServiceReference<?>[] references = 
bundleContext.getServiceReferences(CamelContext.class.getName(), null);
+            if (references != null) {
+                for (ServiceReference<?> reference : references) {
+                    if (reference != null) {
+                        CamelContext camelContext = (CamelContext) 
bundleContext.getService(reference);
+                        if (camelContext != null) {
+                            camelContexts.add(camelContext);
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            LOG.warn("Cannot retrieve the list of Camel contexts.", e);
+        }
+
+        // sort the list
+        camelContexts.sort(Comparator.comparing(CamelContext::getName));
+
+        return camelContexts;
+    }
+
+
+    public CamelContext getCamelContext(String name) throws Exception {
+        for (CamelContext camelContext : getCamelContexts()) {
+            if (camelContext.getName().equals(name)) {
+                return camelContext;
+            }
+        }
+        return null;
+    }
+
+}
diff --git 
a/shell/src/main/java/org/apache/camel/karaf/shell/ContextInflight.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/ContextInflight.java
new file mode 100644
index 00000000..55c45c0a
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/ContextInflight.java
@@ -0,0 +1,94 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.camel.karaf.shell.completers.RouteCompleter;
+import org.apache.camel.spi.ManagementAgent;
+import org.apache.karaf.shell.api.action.*;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@Command(scope = "camel", name = "context-inflight", description = "List 
inflight exchanges")
+@Service
+public class ContextInflight extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The Camel context 
name", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Option(name = "--limit", aliases = "-l", description = "To limit the 
number of exchanges shown", required = false, multiValued = false)
+    int limit = -1;
+
+    @Argument(index = 1, name = "route", description = "The Camel route ID", 
required = false, multiValued = false)
+    @Completion(RouteCompleter.class)
+    String route;
+
+    @Option(name = "--sort", aliases = "-s", description = "Sort by longest 
duration (true) or by exchange id (false)", required = false, multiValued = 
false, valueToShowInHelp = "false")
+    boolean sortByLongestDuration;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(name);
+
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        ShellTable table = new ShellTable();
+        table.column("ExchangeId");
+        table.column("From Route");
+        table.column("Route");
+        table.column("Node");
+        table.column("Elapsed (ms)");
+        table.column("Duration (ms)");
+
+        ManagementAgent agent = 
camelContext.getManagementStrategy().getManagementAgent();
+        if (agent != null) {
+            MBeanServer mBeanServer = agent.getMBeanServer();
+            ObjectName on = new ObjectName(agent.getMBeanObjectDomainName() + 
":type=services,name=DefaultInflightRepository,context=" + 
camelContext.getManagementName());
+            if (mBeanServer.isRegistered(on)) {
+                TabularData list = (TabularData) mBeanServer.invoke(on, 
"browse", new Object[]{route, limit, sortByLongestDuration}, new 
String[]{"java.lang.String", "int", "boolean"});
+                Collection<CompositeData> values = (Collection<CompositeData>) 
list.values();
+                for (CompositeData data : values) {
+                    Map<String, Object> row = new LinkedHashMap<>();
+                    Object exchangeId = data.get("exchangeId");
+                    Object fromRouteId = data.get("fromRouteId");
+                    Object routeId = data.get("routeId");
+                    Object nodeId = data.get("nodeId");
+                    Object elapsed = data.get("elapsed");
+                    Object duration = data.get("duration");
+                    table.addRow().addContent(exchangeId, fromRouteId, 
routeId, nodeId, elapsed, duration);
+                }
+            }
+        }
+
+        table.print(System.out);
+        return null;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/ContextList.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/ContextList.java
new file mode 100644
index 00000000..6d228884
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/ContextList.java
@@ -0,0 +1,66 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.api.management.ManagedCamelContext;
+import org.apache.karaf.shell.api.action.*;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+import java.util.List;
+
+@Command(scope = "camel", name = "context-list", description = "List the Camel 
contexts")
+@Service
+public class ContextList extends CamelCommandSupport implements Action {
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+        table.column("Context");
+        table.column("Status");
+        table.column("Total #");
+        table.column("Failed #");
+        table.column("Inflight #");
+        table.column("Uptime");
+
+        final List<CamelContext> camelContexts = getCamelContexts();
+
+        for (CamelContext camelContext : camelContexts) {
+            ManagedCamelContext mcc = 
camelContext.getCamelContextExtension().getContextPlugin(ManagedCamelContext.class);
+            long exchangesTotal = 0;
+            long exchangesInflight = 0;
+            long exchangesFailed = 0;
+            if (mcc != null && mcc.getManagedCamelContext() != null) {
+                exchangesTotal = 
mcc.getManagedCamelContext().getExchangesTotal();
+                exchangesInflight = 
mcc.getManagedCamelContext().getExchangesInflight();
+                exchangesFailed = 
mcc.getManagedCamelContext().getExchangesFailed();
+            }
+            table.addRow().addContent(camelContext.getName(),
+                    camelContext.getStatus().name(),
+                    exchangesTotal,
+                    exchangesFailed,
+                    exchangesInflight,
+                    camelContext.getUptime());
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}
diff --git 
a/shell/src/main/java/org/apache/camel/karaf/shell/ContextResume.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/ContextResume.java
new file mode 100644
index 00000000..647b39fd
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/ContextResume.java
@@ -0,0 +1,48 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "camel", name = "context-resume", description = "Resumes a 
Camel context")
+@Service
+public class ContextResume extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The name of the 
Camel context", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(name);
+
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        camelContext.resume();
+        return null;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/ContextStart.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/ContextStart.java
new file mode 100644
index 00000000..858809a9
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/ContextStart.java
@@ -0,0 +1,54 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ServiceStatus;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "camel", name = "")
+@Service
+public class ContextStart extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The name of the 
Camel context", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(name);
+
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        if (camelContext.getStatus().equals(ServiceStatus.Suspended)) {
+            camelContext.resume();
+        } else {
+            camelContext.start();
+        }
+
+        return null;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/ContextStop.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/ContextStop.java
new file mode 100644
index 00000000..d78e55fe
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/ContextStop.java
@@ -0,0 +1,49 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "camel", name = "context-stop", description = "Stop a Camel 
context, it becomes unavailable and can not be started again")
+@Service
+public class ContextStop extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The name of the 
Camel context", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(name);
+
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        camelContext.stop();
+
+        return null;
+    }
+
+}
diff --git 
a/shell/src/main/java/org/apache/camel/karaf/shell/ContextSuspend.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/ContextSuspend.java
new file mode 100644
index 00000000..5b8b672a
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/ContextSuspend.java
@@ -0,0 +1,49 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "camel", name = "context-suspend", description = "Suspends a 
Camel context")
+@Service
+public class ContextSuspend extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The name of the 
Camel context", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(name);
+
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        camelContext.suspend();
+
+        return null;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/EndpointList.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/EndpointList.java
new file mode 100644
index 00000000..76e9bee5
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/EndpointList.java
@@ -0,0 +1,95 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.ServiceStatus;
+import org.apache.camel.StatefulService;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.camel.util.URISupport;
+import org.apache.karaf.shell.api.action.*;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+@Command(scope = "camel", name = "endpoint-list", description = "Lists the 
Camel endpoints")
+@Service
+public class EndpointList extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The name of the 
Camel context (support wildcard)", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Option(name = "--decode", aliases = "-d", description = "Whether to 
decode the endpoint uri so its human readable", required = false, multiValued = 
false, valueToShowInHelp = "true")
+    boolean decode = true;
+
+    @Override
+    public Object execute() throws Exception {
+
+        ShellTable table = new ShellTable();
+        table.column("Context");
+        table.column("Uri");
+        table.column("Status");
+
+        CamelContext camelContext = getCamelContext(name);
+
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        List<Endpoint> endpoints = new 
ArrayList<>(camelContext.getEndpoints());
+        // sort routes
+        Collections.sort(endpoints, new Comparator<Endpoint>() {
+            @Override
+            public int compare(Endpoint e1, Endpoint e2) {
+                return e1.getEndpointKey().compareTo(e2.getEndpointKey());
+            }
+        });
+        for (Endpoint endpoint : endpoints) {
+            String uri = endpoint.getEndpointUri();
+            if (decode) {
+                // decode uri so its more human readable
+                uri = URLDecoder.decode(uri, "UTF-8");
+            }
+            // sanitize and mask uri so we don't see passwords
+            uri = URISupport.sanitizeUri(uri);
+            table.addRow().addContent(camelContext.getName(), uri, 
getEndpointState(endpoint));
+        }
+
+        table.print(System.out);
+        return null;
+    }
+
+    private static String getEndpointState(Endpoint endpoint) {
+        // must use String type to be sure remote JMX can read the attribute 
without requiring Camel classes
+        if (endpoint instanceof StatefulService) {
+            ServiceStatus status = ((StatefulService) endpoint).getStatus();
+            return status.name();
+        }
+
+        // assume started if not a ServiceSupport instance
+        return ServiceStatus.Started.name();
+    }
+
+}
diff --git 
a/shell/src/main/java/org/apache/camel/karaf/shell/EndpointStats.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/EndpointStats.java
new file mode 100644
index 00000000..50119642
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/EndpointStats.java
@@ -0,0 +1,122 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.camel.spi.EndpointRegistry;
+import org.apache.camel.spi.RuntimeEndpointRegistry;
+import org.apache.camel.util.URISupport;
+import org.apache.karaf.shell.api.action.*;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+import java.net.URLDecoder;
+
+@Command(scope = "camel", name = "")
+@Service
+public class EndpointStats extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The name of the 
Camel context (support wildcard)", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Option(name = "--filter", aliases = "-f", description = "Filter the list 
by in, out, static, dynamic", required = false, multiValued = true)
+    String[] filter;
+
+    @Option(name = "--decode", aliases = "-d", description = "Whether to 
decode the endpoint uri so its human readable", required = false, multiValued = 
false, valueToShowInHelp = "true")
+    boolean decode = true;
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+        table.column("Context");
+        table.column("Uri");
+        table.column("Route Id");
+        table.column("Direction");
+        table.column("Static");
+        table.column("Dynamic");
+        table.column("Total #");
+
+        CamelContext camelContext = getCamelContext(name);
+
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        if (camelContext.getRuntimeEndpointRegistry() != null) {
+            EndpointRegistry endpointRegistry = 
camelContext.getEndpointRegistry();
+            for (RuntimeEndpointRegistry.Statistic stat : 
camelContext.getRuntimeEndpointRegistry().getEndpointStatistics()) {
+                String uri = stat.getUri();
+                String routeId = stat.getRouteId();
+                String direction = stat.getDirection();
+                boolean isStatic = endpointRegistry.isStatic(uri);
+                boolean isDynamic = endpointRegistry.isDynamic(uri);
+                long hits = stat.getHits();
+
+                if (decode) {
+                    // decode uri so it's more human readable
+                    uri = URLDecoder.decode(uri, "UTF-8");
+                }
+                // sanitize and mask uri so we don't see passwords
+                uri = URISupport.sanitizeUri(uri);
+
+                // should we filter ?
+                if (isValidRow(direction, Boolean.toString(isStatic), 
Boolean.toString(isDynamic))) {
+                    table.addRow().addContent(camelContext.getName(),
+                            uri,
+                            routeId,
+                            direction,
+                            isStatic,
+                            isDynamic,
+                            hits);
+                }
+
+            }
+        }
+
+        table.print(System.out);
+        return null;
+    }
+
+    private boolean isValidRow(String direction, String isStatic, String 
isDynamic) {
+        if (filter == null || filter.length == 0) {
+            return true;
+        }
+
+        boolean answer = false;
+        for (String f : filter) {
+            if ("in".equals(f)) {
+                answer = "in".equals(direction);
+            } else if ("out".equals(f)) {
+                answer = "out".equals(direction);
+            } else if ("static".equals(f)) {
+                answer = "true".equals(isStatic);
+            } else if ("dynamic".equals(f)) {
+                answer = "true".equals(isDynamic);
+            }
+            // all filters must apply to accept when multi valued
+            if (!answer) {
+                return false;
+            }
+        }
+
+        return answer;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/RestApiDoc.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/RestApiDoc.java
new file mode 100644
index 00000000..789a334c
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/RestApiDoc.java
@@ -0,0 +1,53 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "camel", name = "rest-api-doc", description = "List the Camel 
REST services API documentation (requires camel-swagger-java on classpath)")
+@Service
+public class RestApiDoc extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The Camel context 
name where to look for the REST services", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(name);
+
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        String json = camelContext.getRestRegistry().apiDocAsJson();
+        if (json != null) {
+            System.out.println(json);
+        } else {
+            System.out.println("There is no REST service");
+        }
+        return null;
+    }
+
+}
diff --git 
a/shell/src/main/java/org/apache/camel/karaf/shell/RestRegistryList.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/RestRegistryList.java
new file mode 100644
index 00000000..a4cc16de
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/RestRegistryList.java
@@ -0,0 +1,87 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.camel.spi.RestRegistry;
+import org.apache.camel.util.URISupport;
+import org.apache.karaf.shell.api.action.*;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+@Command(scope = "camel", name = "rest-registry-list", description = "Lists 
all Camel REST services enlisted in the Rest Registry from a Camel context")
+@Service
+public class RestRegistryList extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The Camel context 
name where to look for the REST services", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Option(name = "--decode", aliases = "-d", description = "Whether to 
decode the endpoint uri so it's human readable", required = false, multiValued 
= false, valueToShowInHelp = "true")
+    boolean decode = true;
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+        table.column("Url");
+        table.column("Base Path");
+        table.column("Uri Template");
+        table.column("Method");
+        table.column("State");
+
+        CamelContext camelContext = getCamelContext(name);
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        List<RestRegistry.RestService> services = new 
ArrayList<>(camelContext.getRestRegistry().listAllRestServices());
+        Collections.sort(services, new Comparator<RestRegistry.RestService>() {
+            @Override
+            public int compare(RestRegistry.RestService s1, 
RestRegistry.RestService s2) {
+                return s1.getUrl().compareTo(s2.getUrl());
+            }
+        });
+        for (RestRegistry.RestService service : services) {
+            String uri = service.getUrl();
+            if (decode) {
+                // decode uri so it's more human readable
+                uri = URLDecoder.decode(uri, "UTF-8");
+            }
+            // sanitize and mask uri so we don't see passwords
+            uri = URISupport.sanitizeUri(uri);
+            table.addRow().addContent(uri,
+                    service.getBasePath(),
+                    service.getUriTemplate(),
+                    service.getMethod(),
+                    service.getState());
+
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/RouteList.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/RouteList.java
new file mode 100644
index 00000000..149bb856
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/RouteList.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.karaf.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Route;
+import org.apache.camel.ServiceStatus;
+import org.apache.camel.api.management.ManagedCamelContext;
+import org.apache.camel.api.management.mbean.ManagedRouteMBean;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "camel", name = "route-list", description = "List Camel 
routes")
+@Service
+public class RouteList extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The Camel context 
name where to look for the route", required = false, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+        table.column("Context");
+        table.column("Route");
+        table.column("Status");
+        table.column("Total #");
+        table.column("Failed #");
+        table.column("Inflight #");
+        table.column("Uptime");
+
+        CamelContext camelContext = getCamelContext(name);
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        for (Route route : camelContext.getRoutes()) {
+            ManagedCamelContext mcc = 
camelContext.getCamelContextExtension().getContextPlugin(ManagedCamelContext.class);
+            long exchangesTotal = 0;
+            long exchangesInflight = 0;
+            long exchangesFailed = 0;
+            if (mcc != null && mcc.getManagedCamelContext() != null) {
+                ManagedRouteMBean mr = mcc.getManagedRoute(route.getId());
+                exchangesFailed = mr.getExchangesFailed();
+                exchangesInflight = mr.getExchangesInflight();
+                exchangesTotal = mr.getExchangesTotal();
+            }
+            table.addRow().addContent(route.getCamelContext().getName(),
+                    route.getId(),
+                    getRouteState(route),
+                    exchangesTotal,
+                    exchangesFailed,
+                    exchangesInflight,
+                    route.getUptime());
+        }
+
+        table.print(System.out);
+        return null;
+    }
+
+    private String getRouteState(Route route) {
+        // must use String type to be sure remote JMX can read the attribute 
without requiring Camel classes
+        ServiceStatus status = 
route.getCamelContext().getRouteController().getRouteStatus(route.getId());
+        if (status != null) {
+            return status.name();
+        }
+        // assume started if not a ServiceSupport instance
+        return ServiceStatus.Starting.name();
+    }
+
+}
diff --git 
a/shell/src/main/java/org/apache/camel/karaf/shell/RouteResetStats.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/RouteResetStats.java
new file mode 100644
index 00000000..ad44adfa
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/RouteResetStats.java
@@ -0,0 +1,67 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.camel.spi.ManagementAgent;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.util.Set;
+
+@Command(scope = "camel", name = "route-reset-stats", description = "Reset 
route performance stats from a Camel context")
+@Service
+public class RouteResetStats extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The name of the 
Camel context", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String name;
+
+    @Override
+    public Object execute() throws Exception {
+
+        CamelContext camelContext = getCamelContext(name);
+        if (camelContext == null) {
+            System.err.println("Camel context " + name + " not found");
+            return null;
+        }
+
+        ManagementAgent agent = 
camelContext.getManagementStrategy().getManagementAgent();
+        if (agent != null) {
+            MBeanServer mBeanServer = agent.getMBeanServer();
+
+            // reset route mbeans
+            ObjectName query = 
ObjectName.getInstance(agent.getMBeanObjectDomainName() + ":type=routes,*");
+            Set<ObjectName> mBeans = mBeanServer.queryNames(query, null);
+            for (ObjectName routeMBean : mBeans) {
+                String camelId = (String) mBeanServer.getAttribute(routeMBean, 
"CamelId");
+                if (camelId != null && camelId.equals(camelContext.getName())) 
{
+                    mBeanServer.invoke(routeMBean, "reset", new 
Object[]{true}, new String[]{"boolean"});
+                }
+            }
+        }
+
+        return null;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/RouteResume.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/RouteResume.java
new file mode 100644
index 00000000..24984b2b
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/RouteResume.java
@@ -0,0 +1,53 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.camel.karaf.shell.completers.RouteCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "camel", name = "route-resume", description = "Resume a Camel 
route")
+@Service
+public class RouteResume extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The Camel context 
name", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String context;
+
+    @Argument(index = 1, name = "route", description = "The Camel route ID or 
a wildcard expression", required = true, multiValued = false)
+    @Completion(RouteCompleter.class)
+    String route;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(context);
+        if (camelContext == null) {
+            System.err.println("Camel context " + context + " not found");
+            return null;
+        }
+
+        camelContext.getRouteController().resumeRoute(route);
+
+        return null;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/RouteStart.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/RouteStart.java
new file mode 100644
index 00000000..f1e1837e
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/RouteStart.java
@@ -0,0 +1,53 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.camel.karaf.shell.completers.RouteCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "camel", name = "route-start", description = "Start a Camel 
route")
+@Service
+public class RouteStart extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The Camel context 
name", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String context;
+
+    @Argument(index = 1, name = "route", description = "The Camel route ID or 
a wildcard expression", required = true, multiValued = false)
+    @Completion(RouteCompleter.class)
+    String route;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(context);
+        if (camelContext == null) {
+            System.err.println("Camel context " + context + " not found");
+            return null;
+        }
+
+        camelContext.getRouteController().startRoute(route);
+
+        return null;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/RouteStop.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/RouteStop.java
new file mode 100644
index 00000000..61bd4743
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/RouteStop.java
@@ -0,0 +1,53 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.camel.karaf.shell.completers.RouteCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "camel", name = "route-stop", description = "Stop a Camel 
route")
+@Service
+public class RouteStop extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The Camel context 
name", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String context;
+
+    @Argument(index = 1, name = "route", description = "The Camel route ID or 
a wildcard expression", required = true, multiValued = false)
+    @Completion(RouteCompleter.class)
+    String route;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(context);
+        if (camelContext == null) {
+            System.err.println("Camel context " + context + " not found");
+            return null;
+        }
+
+        camelContext.getRouteController().stopRoute(route);
+
+        return null;
+    }
+
+}
diff --git a/shell/src/main/java/org/apache/camel/karaf/shell/RouteSuspend.java 
b/shell/src/main/java/org/apache/camel/karaf/shell/RouteSuspend.java
new file mode 100644
index 00000000..57d8d723
--- /dev/null
+++ b/shell/src/main/java/org/apache/camel/karaf/shell/RouteSuspend.java
@@ -0,0 +1,53 @@
+/*
+ * 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.shell;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.completers.CamelContextCompleter;
+import org.apache.camel.karaf.shell.completers.RouteCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "camel", name = "route-suspend", description = "Suspend a 
Camel route")
+@Service
+public class RouteSuspend extends CamelCommandSupport implements Action {
+
+    @Argument(index = 0, name = "context", description = "The Camel context 
name", required = true, multiValued = false)
+    @Completion(CamelContextCompleter.class)
+    String context;
+
+    @Argument(index = 1, name = "route", description = "The Camel route ID or 
a wildcard expression", required = true, multiValued = false)
+    @Completion(RouteCompleter.class)
+    String route;
+
+    @Override
+    public Object execute() throws Exception {
+        CamelContext camelContext = getCamelContext(context);
+        if (camelContext == null) {
+            System.err.println("Camel context " + context + " not found");
+            return null;
+        }
+
+        camelContext.getRouteController().suspendRoute(route);
+
+        return null;
+    }
+
+}
diff --git 
a/shell/src/main/java/org/apache/camel/karaf/shell/completers/CamelContextCompleter.java
 
b/shell/src/main/java/org/apache/camel/karaf/shell/completers/CamelContextCompleter.java
new file mode 100644
index 00000000..4db84c60
--- /dev/null
+++ 
b/shell/src/main/java/org/apache/camel/karaf/shell/completers/CamelContextCompleter.java
@@ -0,0 +1,47 @@
+/*
+ * 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.shell.completers;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.karaf.shell.CamelCommandSupport;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+import java.util.List;
+
+@Service
+public class CamelContextCompleter extends CamelCommandSupport implements 
Completer {
+
+    @Override
+    public int complete(Session session, CommandLine commandLine, List<String> 
candidates) {
+        try {
+            StringsCompleter delegate = new StringsCompleter();
+            List<CamelContext> camelContexts = this.getCamelContexts();
+            for (CamelContext camelContext : camelContexts) {
+                delegate.getStrings().add(camelContext.getName());
+            }
+            return delegate.complete(session, commandLine, candidates);
+        } catch (Exception e) {
+            // NA
+        }
+        return 0;
+    }
+
+}
diff --git 
a/shell/src/main/java/org/apache/camel/karaf/shell/completers/RouteCompleter.java
 
b/shell/src/main/java/org/apache/camel/karaf/shell/completers/RouteCompleter.java
new file mode 100644
index 00000000..6018ce7d
--- /dev/null
+++ 
b/shell/src/main/java/org/apache/camel/karaf/shell/completers/RouteCompleter.java
@@ -0,0 +1,55 @@
+/*
+ * 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.shell.completers;
+
+import org.apache.camel.Route;
+import org.apache.camel.karaf.shell.CamelCommandSupport;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+import java.util.List;
+
+@Service
+public class RouteCompleter extends CamelCommandSupport implements Completer {
+
+    @Override
+    public int complete(Session session, CommandLine commandLine, List<String> 
candidates) {
+        // grab selected camel context from the first argument
+        String contextName = null;
+        String[] args = commandLine.getArguments();
+        if (args != null && args.length > 1) {
+            // 0 is the command name itself
+            // 1 is the first argument which is the camel context name
+            contextName = args[1];
+        }
+
+        try {
+            StringsCompleter delegate = new StringsCompleter();
+            for (Route route : getCamelContext(contextName).getRoutes()) {
+                delegate.getStrings().add(route.getRouteId());
+            }
+            return delegate.complete(session, commandLine, candidates);
+        } catch (Exception e) {
+            // NA
+        }
+        return 0;
+    }
+
+}

Reply via email to