blob: 76bdaa8b936cb975888e58063eb9bcb0fc3b3885 [file] [log] [blame]
<div class="wiki-content maincontent"><h2 id="Example-ActiveMQ-CPPinAction">ActiveMQ-CPP in Action</h2>
<p>In the example below we create two classes <strong>HolloWorldConsumer</strong> and <strong>HelloWorldProducer</strong> each of which runs in its own thread. The Producer sends TextMessage objects via a <strong>MessageProducer</strong> instance to the ActiveMQ broker. The Consumer receives messages asynchronously from the broker on the same Topic or Queue as the Producer looking for a set number of TextMessages to arrive. </p>
<p>The following example is taken from the source code and shows a basic usage scenario of ActiveMQ-CPP, you can find other examples in the examples folder that ships with the source distribution of ActiveMQ-CPP:</p>
<div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>main.cpp</b></div><div class="codeContent panelContent pdl">
<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[
/*
* 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 &quot;License&quot;); 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 &quot;AS IS&quot; 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.
*/
// START SNIPPET: demo
#include &lt;activemq/library/ActiveMQCPP.h&gt;
#include &lt;decaf/lang/Thread.h&gt;
#include &lt;decaf/lang/Runnable.h&gt;
#include &lt;decaf/util/concurrent/CountDownLatch.h&gt;
#include &lt;decaf/lang/Integer.h&gt;
#include &lt;decaf/lang/Long.h&gt;
#include &lt;decaf/lang/System.h&gt;
#include &lt;activemq/core/ActiveMQConnectionFactory.h&gt;
#include &lt;activemq/util/Config.h&gt;
#include &lt;cms/Connection.h&gt;
#include &lt;cms/Session.h&gt;
#include &lt;cms/TextMessage.h&gt;
#include &lt;cms/BytesMessage.h&gt;
#include &lt;cms/MapMessage.h&gt;
#include &lt;cms/ExceptionListener.h&gt;
#include &lt;cms/MessageListener.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;iostream&gt;
#include &lt;memory&gt;
using namespace activemq::core;
using namespace decaf::util::concurrent;
using namespace decaf::util;
using namespace decaf::lang;
using namespace cms;
using namespace std;
class HelloWorldProducer : public Runnable {
private:
Connection* connection;
Session* session;
Destination* destination;
MessageProducer* producer;
int numMessages;
bool useTopic;
bool sessionTransacted;
std::string brokerURI;
private:
HelloWorldProducer(const HelloWorldProducer&amp;);
HelloWorldProducer&amp; operator=(const HelloWorldProducer&amp;);
public:
HelloWorldProducer(const std::string&amp; brokerURI, int numMessages, bool useTopic = false, bool sessionTransacted = false) :
connection(NULL),
session(NULL),
destination(NULL),
producer(NULL),
numMessages(numMessages),
useTopic(useTopic),
sessionTransacted(sessionTransacted),
brokerURI(brokerURI) {
}
virtual ~HelloWorldProducer(){
cleanup();
}
void close() {
this-&gt;cleanup();
}
virtual void run() {
try {
// Create a ConnectionFactory
auto_ptr&lt;ConnectionFactory&gt; connectionFactory(
ConnectionFactory::createCMSConnectionFactory(brokerURI));
// Create a Connection
connection = connectionFactory-&gt;createConnection();
connection-&gt;start();
// Create a Session
if (this-&gt;sessionTransacted) {
session = connection-&gt;createSession(Session::SESSION_TRANSACTED);
} else {
session = connection-&gt;createSession(Session::AUTO_ACKNOWLEDGE);
}
// Create the destination (Topic or Queue)
if (useTopic) {
destination = session-&gt;createTopic(&quot;TEST.FOO&quot;);
} else {
destination = session-&gt;createQueue(&quot;TEST.FOO&quot;);
}
// Create a MessageProducer from the Session to the Topic or Queue
producer = session-&gt;createProducer(destination);
producer-&gt;setDeliveryMode(DeliveryMode::NON_PERSISTENT);
// Create the Thread Id String
string threadIdStr = Long::toString(Thread::currentThread()-&gt;getId());
// Create a messages
string text = (string) &quot;Hello world! from thread &quot; + threadIdStr;
for (int ix = 0; ix &lt; numMessages; ++ix) {
std::auto_ptr&lt;TextMessage&gt; message(session-&gt;createTextMessage(text));
message-&gt;setIntProperty(&quot;Integer&quot;, ix);
printf(&quot;Sent message #%d from thread %s\n&quot;, ix + 1, threadIdStr.c_str());
producer-&gt;send(message.get());
}
} catch (CMSException&amp; e) {
e.printStackTrace();
}
}
private:
void cleanup() {
if (connection != NULL) {
try {
connection-&gt;close();
} catch (cms::CMSException&amp; ex) {
ex.printStackTrace();
}
}
// Destroy resources.
try {
delete destination;
destination = NULL;
delete producer;
producer = NULL;
delete session;
session = NULL;
delete connection;
connection = NULL;
} catch (CMSException&amp; e) {
e.printStackTrace();
}
}
};
class HelloWorldConsumer : public ExceptionListener,
public MessageListener,
public Runnable {
private:
CountDownLatch latch;
CountDownLatch doneLatch;
Connection* connection;
Session* session;
Destination* destination;
MessageConsumer* consumer;
long waitMillis;
bool useTopic;
bool sessionTransacted;
std::string brokerURI;
private:
HelloWorldConsumer(const HelloWorldConsumer&amp;);
HelloWorldConsumer&amp; operator=(const HelloWorldConsumer&amp;);
public:
HelloWorldConsumer(const std::string&amp; brokerURI, int numMessages, bool useTopic = false, bool sessionTransacted = false, int waitMillis = 30000) :
latch(1),
doneLatch(numMessages),
connection(NULL),
session(NULL),
destination(NULL),
consumer(NULL),
waitMillis(waitMillis),
useTopic(useTopic),
sessionTransacted(sessionTransacted),
brokerURI(brokerURI) {
}
virtual ~HelloWorldConsumer() {
cleanup();
}
void close() {
this-&gt;cleanup();
}
void waitUntilReady() {
latch.await();
}
virtual void run() {
try {
// Create a ConnectionFactory
auto_ptr&lt;ConnectionFactory&gt; connectionFactory(
ConnectionFactory::createCMSConnectionFactory(brokerURI));
// Create a Connection
connection = connectionFactory-&gt;createConnection();
connection-&gt;start();
connection-&gt;setExceptionListener(this);
// Create a Session
if (this-&gt;sessionTransacted == true) {
session = connection-&gt;createSession(Session::SESSION_TRANSACTED);
} else {
session = connection-&gt;createSession(Session::AUTO_ACKNOWLEDGE);
}
// Create the destination (Topic or Queue)
if (useTopic) {
destination = session-&gt;createTopic(&quot;TEST.FOO&quot;);
} else {
destination = session-&gt;createQueue(&quot;TEST.FOO&quot;);
}
// Create a MessageConsumer from the Session to the Topic or Queue
consumer = session-&gt;createConsumer(destination);
consumer-&gt;setMessageListener(this);
std::cout.flush();
std::cerr.flush();
// Indicate we are ready for messages.
latch.countDown();
// Wait while asynchronous messages come in.
doneLatch.await(waitMillis);
} catch (CMSException&amp; e) {
// Indicate we are ready for messages.
latch.countDown();
e.printStackTrace();
}
}
// Called from the consumer since this class is a registered MessageListener.
virtual void onMessage(const Message* message) {
static int count = 0;
try {
count++;
const TextMessage* textMessage = dynamic_cast&lt;const TextMessage*&gt; (message);
string text = &quot;&quot;;
if (textMessage != NULL) {
text = textMessage-&gt;getText();
} else {
text = &quot;NOT A TEXTMESSAGE!&quot;;
}
printf(&quot;Message #%d Received: %s\n&quot;, count, text.c_str());
} catch (CMSException&amp; e) {
e.printStackTrace();
}
// Commit all messages.
if (this-&gt;sessionTransacted) {
session-&gt;commit();
}
// No matter what, tag the count down latch until done.
doneLatch.countDown();
}
// If something bad happens you see it here as this class is also been
// registered as an ExceptionListener with the connection.
virtual void onException(const CMSException&amp; ex AMQCPP_UNUSED) {
printf(&quot;CMS Exception occurred. Shutting down client.\n&quot;);
ex.printStackTrace();
exit(1);
}
private:
void cleanup() {
if (connection != NULL) {
try {
connection-&gt;close();
} catch (cms::CMSException&amp; ex) {
ex.printStackTrace();
}
}
// Destroy resources.
try {
delete destination;
destination = NULL;
delete consumer;
consumer = NULL;
delete session;
session = NULL;
delete connection;
connection = NULL;
} catch (CMSException&amp; e) {
e.printStackTrace();
}
}
};
int main(int argc AMQCPP_UNUSED, char* argv[] AMQCPP_UNUSED) {
activemq::library::ActiveMQCPP::initializeLibrary();
{
std::cout &lt;&lt; &quot;=====================================================\n&quot;;
std::cout &lt;&lt; &quot;Starting the example:&quot; &lt;&lt; std::endl;
std::cout &lt;&lt; &quot;-----------------------------------------------------\n&quot;;
// Set the URI to point to the IP Address of your broker.
// add any optional params to the url to enable things like
// tightMarshalling or tcp logging etc. See the CMS web site for
// a full list of configuration options.
//
// http://activemq.apache.org/cms/
//
// Wire Format Options:
// =========================
// Use either stomp or openwire, the default ports are different for each
//
// Examples:
// tcp://127.0.0.1:61616 default to openwire
// tcp://127.0.0.1:61613?wireFormat=stomp use stomp instead
//
// SSL:
// =========================
// To use SSL you need to specify the location of the trusted Root CA or the
// certificate for the broker you want to connect to. Using the Root CA allows
// you to use failover with multiple servers all using certificates signed by
// the trusted root. If using client authentication you also need to specify
// the location of the client Certificate.
//
// System::setProperty( &quot;decaf.net.ssl.keyStore&quot;, &quot;&lt;path&gt;/client.pem&quot; );
// System::setProperty( &quot;decaf.net.ssl.keyStorePassword&quot;, &quot;password&quot; );
// System::setProperty( &quot;decaf.net.ssl.trustStore&quot;, &quot;&lt;path&gt;/rootCA.pem&quot; );
//
// The you just specify the ssl transport in the URI, for example:
//
// ssl://localhost:61617
//
std::string brokerURI =
&quot;failover:(tcp://localhost:61616)&quot;;
//============================================================
// set to true to use topics instead of queues
// Note in the code above that this causes createTopic or
// createQueue to be used in both consumer an producer.
//============================================================
bool useTopics = true;
bool sessionTransacted = false;
int numMessages = 2000;
long long startTime = System::currentTimeMillis();
HelloWorldProducer producer(brokerURI, numMessages, useTopics);
HelloWorldConsumer consumer(brokerURI, numMessages, useTopics, sessionTransacted);
// Start the consumer thread.
Thread consumerThread(&amp;consumer);
consumerThread.start();
// Wait for the consumer to indicate that its ready to go.
consumer.waitUntilReady();
// Start the producer thread.
Thread producerThread(&amp;producer);
producerThread.start();
// Wait for the threads to complete.
producerThread.join();
consumerThread.join();
long long endTime = System::currentTimeMillis();
double totalTime = (double)(endTime - startTime) / 1000.0;
consumer.close();
producer.close();
std::cout &lt;&lt; &quot;Time to completion = &quot; &lt;&lt; totalTime &lt;&lt; &quot; seconds.&quot; &lt;&lt; std::endl;
std::cout &lt;&lt; &quot;-----------------------------------------------------\n&quot;;
std::cout &lt;&lt; &quot;Finished with the example.&quot; &lt;&lt; std::endl;
std::cout &lt;&lt; &quot;=====================================================\n&quot;;
}
activemq::library::ActiveMQCPP::shutdownLibrary();
}
// END SNIPPET: demo
]]></script>
</div></div></div>