Listing Camel Routes deployed on ServiceMix

Here’s a simple groovy script to show deployed Apache Camel routes. It uses JMX to query the description of routes available.

import javax.management.*
import javax.management.remote.*
import javax.lang.management.*

def prettyPrint = { s ->
  ps = ""
  level = 0
  for(c in s){
    if(c == '['){
      level++
      ps += "[\n".padRight(level*4," ")
    } else if(c == ']'){
      level--
      ps += "]"
    } else if(c == ','){
      ps += ",\n".padRight(level*4," ")
    } else {
      ps += c
    }
  }
  return ps
}

def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:1099/karaf-root'
def jmxUsername = 'smx'
def jmxPassword = 'smx'

def env = [(JMXConnector.CREDENTIALS): [jmxUsername,jmxPassword] as String[]]
def jmxUrl = new JMXServiceURL(serverUrl)
def connect = JMXConnectorFactory.connect(jmxUrl,env)
def server = connect.MBeanServerConnection
def query = new ObjectName('org.apache.camel:type=routes,*')
def routes = server.queryNames(query,null)

routes.each { route ->
	def routeBean = new GroovyMBean(server,route)
	printf "%250s\n", prettyPrint(routeBean.Description)
}

Here’s an example of the output generated by this script:

EventDrivenConsumerRoute[
  Endpoint[
      activemq://topic:STOCKS.TOPIC?clientId=1&durableSubscriptionName=dsn1&selector=SE%3D%27NASDAQ%27] -> Instrumentation:route[
      UnitOfWork(Pipeline[
          [
              Channel[
                  sendTo(Endpoint[
                      log://stocks.out?showAll=true])],
               Channel[
                  sendTo(Endpoint[
                      activemq://queue:STOCKS.NASDAQ])]]])]]

EventDrivenConsumerRoute[
  Endpoint[
      activemq://queue:STOCKS.IN] -> Instrumentation:route[
      UnitOfWork(Pipeline[
          [
              Channel[
                  sendTo(Endpoint[
                      log://stocks.in?showAll=true])],
               Channel[
                  sendTo(Endpoint[
                      activemq://topic:STOCKS.TOPIC])]]])]]

Listing ActiveMQ queues with JMX and Groovy

The following groovy script displays a list of queues in ActiveMQ with some statistics per queue.

import javax.management.*
import javax.management.remote.*
import javax.lang.management.*

def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi'

def env = [(JMXConnector.CREDENTIALS): ["smx","smx"] as String[]]
def jmxUrl = new JMXServiceURL(serverUrl)
def connect = JMXConnectorFactory.connect(jmxUrl,env)
def server = connect.MBeanServerConnection

def query = new ObjectName('org.apache.activemq:Type=Queue,*')
def queues = server.queryNames(query,null)
printf "%-50s, %7s, %7s, %7s, %7s, %7s, %7s, %7s, %7s, %7s\n", "Name", "Avg QT", "Max QT", "Min QT", "Enq Cnt", "Dsp Cnt", "Exp Cnt", "Inf Cnt", "Consumrs", "Producr"

printf "%-50s, %7s, %7s, %7s, %7s, %7s, %7s, %7s, %7s, %7s\n", "----", "------", "------", "------", "-------", "-------", "-------", "-------", "--------", "-------"

queues.each { queue ->
        def queueBean = new GroovyMBean(server,queue)
        printf "%-50s, %7.2g, %7.2g, %7.2g, %7s, %7s, %7s, %7s, %7s, %7s\n",
                queueBean.Name,
                queueBean.AverageEnqueueTime as Float, queueBean.MaxEnqueueTime as Float, queueBean.MinEnqueueTime as Float,

                queueBean.EnqueueCount, queueBean.DispatchCount, queueBean.ExpiredCount, queueBean.InFlightCount,
                queueBean.ConsumerCount, queueBean.ProducerCount
}

Listing Camel Routes using JMX and Groovy

The following groovy script can be used to list all Camel routes on a running servicemix. Per route it will display state of the route, and some statistics.


import javax.management.*
import javax.management.remote.*
import javax.lang.management.*

def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:1099/karaf-root'

def env = [(JMXConnector.CREDENTIALS): ["smx","smx"] as String[]]
def jmxUrl = new JMXServiceURL(serverUrl)
def connect = JMXConnectorFactory.connect(jmxUrl,env)
def server = connect.MBeanServerConnection

def query = new ObjectName('org.apache.camel:type=routes,*')
def routes = server.queryNames(query,null)
printf "%-30s, %-10s, %7s, %7s, %7s, %7s, %7s, %7s, %7s\n", "RouteId", "State", "Ex comp", "Ex Fail", "Ex Tot", "Last T", "Max T", "Mean T", "Total T"
printf "%-30s, %-10s, %7s, %7s, %7s, %7s, %7s, %7s, %7s\n", "-------", "-----", "-------", "-------", "------", "------", "-----", "------", "-------"
routes.each { route ->
	def routeBean = new GroovyMBean(server,route)
	printf "%-30s, %-10s, %7s, %7s, %7s, %7s, %7s, %7s, %7s\n",
		routeBean.RouteId, routeBean.State,
		routeBean.ExchangesCompleted, routeBean.ExchangesFailed, routeBean.ExchangesTotal,
		routeBean.LastProcessingTime, routeBean.MaxProcessingTime, routeBean.MeanProcessingTime, routeBean.TotalProcessingTime
}

Adding an ActiveMQ broker in ServiceMix

Out of the box ServiceMix comes with a preconfigured ActiveMQ broker, which is started when you start ServiceMix.

karaf@root> osgi:list | grep mq
[  43] [Active     ] [Created     ] [       ] [   60] activemq-core (5.4.1.fuse-00-00)
[  45] [Active     ] [            ] [       ] [   60] activemq-console (5.4.1.fuse-00-00)
[  46] [Active     ] [            ] [       ] [   60] activemq-ra (5.4.1.fuse-00-00)
[  47] [Active     ] [            ] [       ] [   60] activemq-pool (5.4.1.fuse-00-00)
[  48] [Active     ] [Created     ] [       ] [   60] activemq-karaf (5.4.1.fuse-00-00)
[  53] [Resolved   ] [            ] [       ] [   60] activemq-blueprint (5.4.1.fuse-00-00)
[  54] [Active     ] [Created     ] [       ] [   60] activemq-broker.xml (0.0.0)

Bundle 54 is the default broker. You can configure it by changing the file SERVICEMIX_HOME/etc/activemq-broker.xml

You can add an extra broker by using the command activemq:create-broker in the ServiceMix shell:

karaf@root> activemq:create-broker --name=test
Creating file: @|green C:\java\apache-servicemix-4.3.0-fuse-02-00\deploy\test-broker.xml|

Default ActiveMQ Broker (test) configuration file created at: C:\java\apache-servicemix-4.3.0-fuse-02-00\deploy\test-broker.xml
Please review the configuration and modify to suite your needs.

This command creates a configuration file for your new browser, for this example it’s called SERVICEMIX_HOME/deploy/test-broker.xml

You need to change it because it’s using the same ports as the default broker. Look for the following lines in the configuration file and change the ports to something unused.

...
        <!-- The transport connectors ActiveMQ will listen to -->
        <transportConnectors>
            <transportConnector name="openwire" uri="tcp://localhost:61816"/>
            <transportConnector name="stomp" uri="stomp://localhost:61813"/>
        </transportConnectors>
    </broker>
    <bean id="activemqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://localhost:61816" />
    </bean>
...

Next, you need to install the activemq-spring feature to avoid as the broker configuration file generated uses spring, instead of osgi blueprint as the default does.

karaf@root> features:install activemq-spring

If you list the ActiveMQ brokers, you’ll see that you have two:

karaf@root> activemq:list --jmxlocal
BrokerName = test
BrokerName = default

ActiveMQ in ServiceMix jmx problem

When you try to list your ActiveMQ brokers in ServiceMix you may run into the following jmx problem:

karaf@root> activemq:list
Connecting to JMX URL: service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
ERROR: java.lang.RuntimeException: Failed to execute list task. Reason: java.io.IOException: Failed to retrieve RMIServer stub: javax.naming.NameNotFoundException: jmxrmi
java.lang.RuntimeException: Failed to execute list task. Reason: java.io.IOException: Failed to retrieve RMIServer stub: javax.naming.NameNotFoundException: jmxrmi
        at org.apache.activemq.console.command.ListCommand.runTask(ListCommand.java:52)
        at org.apache.activemq.console.command.AbstractCommand.execute(AbstractCommand.java:57)
        at org.apache.activemq.console.command.AbstractJmxCommand.execute(AbstractJmxCommand.java:292)
        at org.apache.activemq.karaf.commands.ActiveMQCommandSupport.doExecute(ActiveMQCommandSupport.java:46)
        at org.apache.karaf.shell.console.OsgiCommandSupport.execute(OsgiCommandSupport.java:41)
        at org.apache.felix.gogo.commands.basic.AbstractCommand.execute(AbstractCommand.java:35)
        at org.apache.felix.gogo.runtime.shell.CommandProxy.execute(CommandProxy.java:50)
        at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:229)
        at org.apache.felix.gogo.runtime.shell.Closure.executeStatement(Closure.java:162)
        at org.apache.felix.gogo.runtime.shell.Pipe.run(Pipe.java:101)
        at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:79)
        at org.apache.felix.gogo.runtime.shell.CommandSessionImpl.execute(CommandSessionImpl.java:71)
        at org.apache.karaf.shell.console.jline.Console.run(Console.java:181)
        at java.lang.Thread.run(Thread.java:619)
Error executing command: java.io.IOException: Failed to retrieve RMIServer stub: javax.naming.NameNotFoundException: jmxrmi

The solution is simple, add the option –jmxlocal, and documented in Deploying into the OSGi Container:

karaf@root> activemq:list --jmxlocal
BrokerName = default

Monitoring Camel routes with JMX

ServiceMix and Camel expose a lot of information through jmx mbeans. You can use jconsole to access this information.

Start jconsole and connect to a running servicemix instance. Look for the entry with karaf in the name:

JConsole: new connection

In the mbeans tab you’ll find a node for Apache Camel. Here you’ll find all your routes, endpoints, services and processors:

Route MBean

You can name your routes using the id method, this makes it easier to find it in jconsole:

public class TestRouteBuilder extends RouteBuilder {

    public void configure() throws Exception {
        from("file:///tmp/testin").id("fileToLogRoute").to("log:filereceived?showAll=true");
    }

}

THe attributes section shows you a lot of information about the exchanges that have been handled by the route, for example number of exchanges completed, number of failed exchanges. It also shows you the status of a route.

Route Attributes

The methods sections enables you to start and stop a route:

Route operations

Adding a maven repository for installing features to ServiceMix

I’m running ServiceMix on a machine which doesn’t have internet access, so installing and upgrading features is a bit hard. You can, however, install features from an internal maven repository like Nexus. This post explains how you can configure which maven repositories should be used by ServiceMix.

The OSGI implementation of ServiceMix (Apache Felix/Karaf) has a console which you can use to update the configuration. You can see the currently active configurations as follows:

karaf@root> config:list
...
----------------------------------------------------------------
Pid:            org.ops4j.pax.url.mvn
BundleLocation: mvn:org.ops4j.pax.url/pax-url-mvn/1.1.2
Properties:
   service.pid = org.ops4j.pax.url.mvn
   org.ops4j.pax.url.mvn.defaultRepositories = file:/opt/fuse/fuse-4.2/system@snapshots
   felix.fileinstall.filename = org.ops4j.pax.url.mvn.cfg
   org.ops4j.pax.url.mvn.repositories = http://repo1.maven.org/maven2,http://repo.fusesource.com/maven2, \
  http://repo.fusesource.com/maven2-snapshot@snapshots@noreleases, \
  http://repository.apache.org/content/groups/snapshots-group@snapshots@noreleases, \
  http://repository.ops4j.org/maven2, \
  http://svn.apache.org/repos/asf/servicemix/m2-repo, \
  http://repository.springsource.com/maven/bundles/release, \

http://repository.springsource.com/maven/bundles/external

...

The configuration with Pid org.ops4j.pax.url.mvn is used to tell ServiceMix where to look for features. You can add your own Maven repository to org.ops4j.pax.url.mvn.repositories.

First you need to tell karaf that you want to edit the configuration with pid org.ops4j.pax.url.mvn:

karaf@root> config:edit org.ops4j.pax.url.mvn

Now you can modify the value of org.ops4j.pax.url.mvn.repositories:

karaf@root> config:propset org.ops4j.pax.url.mvn.repositories \

http://<internal-maven-repo>/nexus/content/groups/public

Save the configuration updates, make sure the changes are visible to the bundles that use it:

karaf@root> config:update

You can see the updated configuration using config:list:

karaf@root> config:list
----------------------------------------------------------------
Pid:            org.ops4j.pax.url.mvn
BundleLocation: mvn:org.ops4j.pax.url/pax-url-mvn/1.1.2
Properties:
   service.pid = org.ops4j.pax.url.mvn
   org.ops4j.pax.url.mvn.defaultRepositories = file:/opt/fuse/fuse-4.2/system@snapshots
   felix.fileinstall.filename = org.ops4j.pax.url.mvn.cfg
   org.ops4j.pax.url.mvn.repositories = \

http://<internal-maven-repo>/nexus/content/groups/public

Using this modified configuration i can now install features from my internal maven repository. This means i need to proxy all the required external maven repositories in my internal maven repository.