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