Logo Computer scientist,
engineer, and educator
• Articles • Articles about computing • Articles about software development • Apache integration software

Writing a C++ client for ActiveMQ from the ground up

This article describes how to create a very simple ActiveMQ client in C++, using the Apache CMS ("C++ Messaging Service") library. All steps are carried out on the command line although, of course, you would probably automate the build process using Makefiles or similar tools in practice. The purpose of this painful detail is to make clear the exact process involved.

This article assumes that you're working on a modern Linux system; the specific instructions are for Fedora 20, but there should be only minor differences on other distributions (apt-get instead of yum install, for example). It's possible to build the CMS library on Windows, but this is beyond the scope of this article.

I assume some (not much) familiarity with the C++ programming language and the use of the g++ compiler at the command line. This article does not attempt to explain the CMS API in detail. Java programmers will be relieved to know that it's conceptually the same as the JMS API; the programming idiom is C++, of course.

In this example, I won't install the CMS library at the system level. Instead, after building, the library will be copied to the same directory as the C++ program and used there. The reason for this, apart from obviating the need for root access, is to make it possible to work with several different versions of CMS, if that should be necessary. It also makes it clearer what specific software components are required by the client application.

Building the ActiveMQ CMS library

CMS has a number of dependencies which will need to be installed first. On a modern Fedora/RHEL system it should not be necessary to build any dependencies from source, as development packages are available in the repositories.

Install dependencies

For the purpose of this article I assume that GNU C/C++ compiler tools and libraries are installed. On a modern Fedora/RHEL system, the only additional dependencies you should need are the development packages for OpenSSL and the Apache Portable Runtime.
$ sudo yum install openssl-devel
$ sudo yum install apr-devel

Obtain and build CMS

Get the source code from the CMS website. At the time of writing, the latest version of CMS is 3.8.2, and the Linux source bundle is activemq-cpp-library-3.8.4-src.tar.bz2.

Unpack the source and change to the source directory:

$ tar xvfj /path/to/activemq-cpp-library-3.8.2.tar.bz2
$ cd activemq-cpp-library-3.8.2.tar
Configure the source (and create the Makefile):
$ ./configure
Note that the ./configure utility has many switches, mostly concerned with installation location. Since we won't be installing anything at the system level, the default settings should be fine.

Now build the library:

$ cd src/main
$ make
This will take some time, even on a fast machine. In the end, you should end up with the libraries (both static and dynamic) in the .libs directory. Header (.h) files are in various subdirectories of src/main, and their locations will need to be given when building the ActiveMQ client program.

Coding, building, and running client

Coding

This simple client connects to the broker and consumes a single text message from the queue called __test_destination. You'll need to modify it to use the host and port number of your own ActiveMQ broker. In this example, the C++ program has a single source file, saved as testconsumer.cpp. I hope the comments make it reasonably self-explanatory; certainly the basic principles should be recognizable by anybody who is familiar with the Java JMS API.

The source file is part of the source code bundle, available from the Downloads section at the end of this article.

#include <stdio.h>
#include <string>
#include <activemq/core/ActiveMQConnectionFactory.h>
#include <activemq/core/ActiveMQConnection.h>
#include <activemq/transport/DefaultTransportListener.h>
#include <activemq/library/ActiveMQCPP.h>

using namespace activemq;
using namespace activemq::core;
using namespace activemq::transport;
using namespace cms;
using namespace std;

int main (int argc, char **argv)
  {
  // URI of the message broker — set this to be appropriate for your broker
  string brokerURI =
        "tcp://192.168.1.114:61616";

  // JMS queue name
  string dest = "__test_destination";

  // Initialize CMS
  activemq::library::ActiveMQCPP::initializeLibrary();

  // Get a connection factory for the specified broker URI 
  ActiveMQConnectionFactory* connectionFactory =
                new ActiveMQConnectionFactory (brokerURI);

  // Connect to the broker
  Connection *connection =
    connectionFactory->createConnection();

  connection->start();

  // Creation of the session, destination, and consumer are much
  //  the same as in the JMS API
  Session *session = connection->createSession (Session::AUTO_ACKNOWLEDGE);
  Destination *destination = session->createQueue (dest);
  MessageConsumer *consumer = session->createConsumer (destination);

  // Consume a text message
  TextMessage *m = (TextMessage*) consumer->receive();

  // Print the message contents. Note that c_str() gets the C 
  //  represetntation of the C++ string object
  cout << "Received: " << m->getText() << endl;

  // Tidy up. Don't have to do this in Java :)
  delete m;
  delete destination;
  delete session;
  delete connection;
  delete connectionFactory;

  return 0;
  }

Building

To build the client we must compile the C++ source to an object file, specifying the location of the CMS header files. These will be under the directory src/main, in the CMS build directory. In my example, the CMS build directory is /home/kevin/source/activemq-cpp-library-3.8.2/, so I compile the C++ program to testconsumer.o as follows:
$ export APR_INCLUDE=/usr/include/apr-1
$ export CMS_HOME=/home/kevin/source/activemq-cpp-library-3.8.2/
$ g++ -I $APR_INCLUDE -I $CMS_HOME/src/main -g -o testconsumer.o -c testconsumer.cpp 
Note that it is also necessary to include the location of the Apache Portable Runtime header files (/usr/include/apr-1 in my case).

The next step is to link the .o file against the CMS library.

$ g++ -L $(CMS_HOME)/src/main/.libs/ -g -o testconsumer testconsumer.o -lactivemq-cpp -lssl
Notice that we need to link the openssl (-lssl) library as well, as CMS uses OpenSSL for SSL operations.

All being well, the link process should have created the executable testconsumer, which we can run.

Running the client

I'm not installing the CMS library at the system level, so it's location will need to be specified at runtime. In this example, I just copy the library to the same directory as the client program (any suitable directory will do, so long as you know where it is.)
$ cp $CMS_HOME/src/main/.libs/libactivemq-cpp.so.18.0.2 .
$ ln -sf libactivemq-cpp.so.18.0.2 libactivemq-cpp.so.18
Note that libactivemq-cpp.so.18.0.2 is the name of the library created by the CMS build process but, owing to the oddities of library versioning on Linux, the loader will look for libactivemq-cpp.so.18. Making a symbolic link to the original library is more idiomatically Linux-like, but of course you could just rename the file when you copy it.

We use the LD_LIBRARY_PATH environment variable to indicate the directory containing the CMS library at runtime like this:

$ LD_LIBRARY_PATH=. ./testconsumer
"." is appropriate here since the library is in the current directory.

Discussion

This article has described the creation of what must be the simplest possible C++ application that acts as a client to Apache ActiveMQ. The time-consuming part is building the CMS library from source, but that only needs to be done once for a particular platform and library version.

Downloads

C++ source code bundle
Copyright © 1994-2015 Kevin Boone. Updated Apr 15 2015