Created Documentation for Writing a CPP QMF console application ---------------------------------------------------------------
Key: QPID-2411 URL: https://issues.apache.org/jira/browse/QPID-2411 Project: Qpid Issue Type: Improvement Components: Documentation Reporter: Andrew English Priority: Minor I have pasted in my initial draft of the documentation for creating a QMF console application in C++. If this is still needed, I will complete the sections on calling methods and asynchronous notifications. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html><head> <link type="text/css" rel="stylesheet" href="qmf-python-console-tutorial_files/space.css"> <style type="text/css"> .footer { background-image: url('http://cwiki.apache.org/confluence/images/border/border_bottom.gif'); background-repeat: repeat-x; background-position: left top; padding-top: 4px; color: #666; clear: both; } .left { padding-top: 5px; float : left; width : 15em; } .pagecontent { float: left; width: 70%; } </style> <script type="text/javascript" language="javascript"> var hide = null; var show = null; var children = null; function init() { /* Search form initialization */ var form = document.forms['search']; if (form != null) { form.elements['domains'].value = location.hostname; form.elements['sitesearch'].value = location.hostname; } /* Children initialization */ hide = document.getElementById('hide'); show = document.getElementById('show'); children = document.all != null ? document.all['children'] : document.getElementById('children'); if (children != null) { children.style.display = 'none'; show.style.display = 'inline'; hide.style.display = 'none'; } } function showChildren() { children.style.display = 'block'; show.style.display = 'none'; hide.style.display = 'inline'; } function hideChildren() { children.style.display = 'none'; show.style.display = 'inline'; hide.style.display = 'none'; } </script> <title>Apache Qpid: Open Source AMQP Messaging - QMF Cpp Console Tutorial</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body onload="init()"> <table width="100%" border="0" cellpadding="2" cellspacing="0"> <tbody><tr class="topBar"> <td class="topBarDiv" valign="middle" align="left" nowrap="nowrap"> <a href="http://qpid.apache.org/index.html" title="Apache Qpid">Apache Qpid</a> > <a href="http://qpid.apache.org/index.html" title="Index">Index</a> > <a href="http://qpid.apache.org/developer-pages.html" title="Developer Pages">Developer Pages</a> > <a href="http://qpid.apache.org/qpid-management-framework.html" title="Qpid Management Framework">Qpid Management Framework</a> > <a href="" title="QMF Cpp Console Tutorial">QMF Cpp Console Tutorial</a> </td> <td valign="middle" align="right" nowrap="nowrap"> <form name="search" action="http://www.google.com/search" method="get"> <input name="ie" value="UTF-8" type="hidden"> <input name="oe" value="UTF-8" type="hidden"> <input name="domains" value="qpid.apache.org" type="hidden"> <input name="sitesearch" value="qpid.apache.org" type="hidden"> <input name="q" maxlength="255" type="text"> <input name="btnG" value="Google Search" type="submit"> </form> </td> </tr> </tbody></table> <div id="PageContent"> <div class="pageheader" style="padding: 6px 0px 0px;"> <div> <table width="90%" border="0"> <tbody><tr> <td align="left"> <a href="http://qpid.apache.org/"> <img src="qmf-python-console-tutorial_files/qpid-logo.png" width="225" border="0" height="69"></a> </td> <td> </td> <td align="right"> <a href="http://www.apache.org/"> <img src="qmf-python-console-tutorial_files/asf-logo.png" width="225" border="0" height="69"></a></td> </tr> </tbody></table> </div> </div> <!-- <div class="pagesubheading" style="margin: 0px 10px 0px 10px;"> Added by <a href="/confluence/display/~tross">Ted Ross</a>, last edited by <a href="/confluence/display/~tross">Ted Ross</a> on Mar 03, 2009 (<a class="noprint" href="/confluence/pages/diffpages.action?pageId=108629&originalId=111632">view change</a>) </div> --> <div class="left"> <div class="panel" style="border: 1px solid rgb(32, 32, 128);"><div class="panelContent" style=""> <h3><a name="Navigation-ApacheQpid"></a>Apache Qpid</h3> <p> <a href="http://qpid.apache.org/index.html" title="Index">Home</a><br> <a href="http://qpid.apache.org/download.html" title="Download">Download</a><br> <a href="http://qpid.apache.org/getting-started.html" title="Getting Started">Getting Started</a> <br> <a href="http://qpid.apache.org/documentation.html" title="Documentation">Documentation</a><br> <a href="http://qpid.apache.org/mailing-lists.html" title="Mailing Lists">Mailing Lists</a><br> <a href="http://issues.apache.org/jira/browse/qpid" rel="nofollow">Issue Reporting</a><br> <a href="http://qpid.apache.org/faq.html" title="FAQ">FAQ/How to</a></p> <h3><a name="Navigation-Resources"></a>Resources</h3> <p> <a href="http://qpid.apache.org/getting-involved.html" title="Getting Involved">Getting Involved</a><br> <a href="http://qpid.apache.org/qpid-integrations.html" title="Qpid Integrations">Qpid Integrated with..</a><br> <a href="http://qpid.apache.org/source-repository.html" title="Source Repository">Source Repository</a><br> <a href="http://qpid.apache.org/building.html" title="Building">Building Qpid</a><br> <a href="http://qpid.apache.org/developer-pages.html" title="Developer Pages">Developer Pages</a><br> <a href="http://qpid.apache.org/qpid-management-framework.html" title="Qpid Management Framework">QMF</a></p> <h3><a name="Navigation-AboutQpid"></a>About Qpid</h3> <p> <a href="http://qpid.apache.org/people.html" title="People">People</a><br> <a href="http://qpid.apache.org/license.html" title="License">License</a><br> <a href="http://qpid.apache.org/project-status.html" title="Project Status">Project Status</a><br> <a href="http://qpid.apache.org/acknowledgments.html" title="Acknowledgments">Acknowledgments</a></p> <h3><a name="Navigation-AboutAMQP"></a>About AMQP</h3> <p> <a href="http://qpid.apache.org/amqp-advanced-message-queueing-protocol.html" title="AMQP (Advanced Message Queueing Protocol)">What is AMQP ?</a><br> <a href="http://qpid.apache.org/amqp-advanced-message-queueing-protocol.html" title="AMQP (Advanced Message Queueing Protocol)">AMQP Specification Download</a></p> <p><img src="qmf-python-console-tutorial_files/AMQP_logo_71px-small.jpg" align="absmiddle" border="0"></p> </div></div> </div> <div class="pagecontent"> <div class="wiki-content"> <div> <ul> <li><a href="#QMFCPPConsoleTutorial-PrerequisiteInstallQpidMessaging">Prerequisite - Install Qpid Messaging</a></li> <li><a href="#QMFCPPConsoleTutorial-SynchronousConsoleOperations">Synchronous Console Operations</a></li> <ul> <li><a href="#QMFCPPConsoleTutorial-CreatingaQMFConsoleSessionandAttachingtoaBroker">Creating a QMF Console Session and Attaching to a Broker</a></li> <li><a href="#QMFCPPConsoleTutorial-AccessingManagedObjects">Accessing Managed Objects</a></li> <ul> <li><a href="#QMFCPPConsoleTutorial-ViewingPropertiesandStatisticsofanObject">Viewing Properties and Statistics of an Object</a></li> <li><a href="#QMFCPPConsoleTutorial-InvokingMethodsonanObject">Invoking Methods on an Object</a></li> </ul> </ul> <li><a href="#QMFPythonConsoleTutorial-AsynchronousConsoleOperations">Asynchronous Console Operations</a></li> <ul> <li><a href="#QMFPythonConsoleTutorial-CreatingaConsoleClasstoReceiveAsynchronousData">Creating a Console Class to Receive Asynchronous Data</a></li> <li><a href="#QMFPythonConsoleTutorial-ReceivingEvents">Receiving Events</a></li> <li><a href="#QMFPythonConsoleTutorial-ReceivingObjects">Receiving Objects</a></li> <li><a href="#QMFPythonConsoleTutorial-AsynchronousMethodCallsandMethodTimeouts">Asynchronous Method Calls and Method Timeouts</a></li> </ul> <li><a href="#QMFPythonConsoleTutorial-DiscoveringwhatKindsofObjectsareAvailable">Discovering what Kinds of Objects are Available</a></li> </ul></div> <h1><a name="QMFPythonConsoleTutorial-PrerequisiteInstallQpidMessaging"></a>Prerequisite - Install Qpid Messaging</h1> <p>QMF uses AMQP Messaging (QPid) as its means of communication. To use QMF, Qpid messaging must be installed somewhere in the network. Qpid can be downloaded as source from Apache, is packaged with a number of Linux distributions, and can be purchased from commercial vendors that use Qpid. Please see <a href="http://qpid.apache.org/download.html" title="Download">Download</a> for information as to where to get Qpid Messaging.</p> <p>Qpid Messaging includes a message broker (qpidd) which typically runs as a daemon on a system. It also includes client bindings in various programming languages. The C++-language client library includes the source for the QMF console libraries needed for this tutorial.</p> <p>Please note that Qpid Messaging has two broker implementations. One is implemented in C++ and the other in Java. At press time, QMF is supported only by the C++ broker.</p> <p>If the goal is to get the tutorial examples up and running as quickly as possible, all of the Qpid components can be installed on a single system (even a laptop). For more realistic deployments, the broker can be deployed on a server and the client/QMF libraries installed on other systems.</p> <h1><a name="QMFCPPConsoleTutorial-SynchronousConsoleOperations"></a>Synchronous Console Operations</h1> <p>The C++ console API for QMF can be used in a synchronous style, an asynchronous style, or a combination of both. Synchronous operations are conceptually simple and are well suited for user-interactive tasks. All operations are performed in the context of a C++ function call. If communication over the message bus is required to complete an operation, the function call blocks and waits for the expected result (or timeout failure) before returning control to the caller.</p> <h2><a name="QMFCPPConsoleTutorial-CreatingaQMFConsoleSessionandAttachingtoaBroker"></a>Creating a QMF Console Session and Attaching to a Broker</h2> <p>For the purposes of this tutorial, code examples will be shown in snippets revelant to the current task.</p> <p>We will begin by including the required libraries. If the QMF libraries are installed in the lib directory, they can be referenced when building and linking the application:</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre> g++ -c -I/usr/include/qpid-boost qmfagent.cpp -o qmfagent.o g++ -lqpidclient -lqmfconsole ./qmfagent.o -o qmfagent </pre> </div></div> In the source, they should be included as follows: <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>#include <qpid/console/SessionManager.h> namespace qmf = qpid::console; </pre> </div></div> <p>We must now create a <em>Session</em> object to manage this QMF console session.</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>qmf::SessionManager sessMgr; </pre> </div></div> <p>If no arguments are supplied to the creation of <em>Session</em>, it defaults to synchronous-only operation. It also defaults to user-management of connections. More on this in a moment.</p> <p>We will now establish a connection to the messaging broker. If the broker daemon is running on the local host, simply use the following:</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>qmf::Broker* broker = sessMgr.addBroker(); </pre> </div></div> <p>If the messaging broker is on a remote host, supply the URL to the broker in the <em>addBroker</em> function call. Here's how to connect to a local broker using the URL.</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>qmf::Broker* broker = sessMgr.addBroker("amqp://localhost"); </pre> </div></div> <p>A <em>ConnectionSettings</em> object can also be passed to the <em>addBroker</em> function call.</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>qmf_::SessionManager sessMgr; qc::ConnectionSettings settings; settings.host = host; settings.port = port; qmf::Broker* broker = sessMgr.addBroker(settings); </pre> </div></div> <p>The call to <em>addBroker</em> is synchronous and will return only after the connection has been successfully established or has failed. If a failure occurs, <em>addBroker</em> will raise an exception.</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>try { qmf::Broker* broker = sessMgr.addBroker("amqp://localhost:1000"); } catch(const std::exception& error) { std::cout << "Failed to connect: " << error.what() << std::endl; } </pre> </div></div> <p>This operation fails because there is no Qpid Messaging broker listening on port 1000 (the default port for qpidd is 5672).</p> <p>If preferred, the QMF session can manage the connection for you. In this case, <em>addBroker</em> returns immediately and the session attempts to establish the connection in the background. This will be covered in detail in the section on asynchronous operations.</p> <h2><a name="QMFCPPConsoleTutorial-AccessingManagedObjects"></a>Accessing Managed Objects</h2> <p>The C++ console API provides access to remotely managed objects via a <em>proxy</em> model. The API gives the client an object that serves as a proxy representing the "real" object being managed on the agent application. Operations performed on the proxy result in the same operations on the real object.</p> <p>The following examples assume prior knowledge of the kinds of objects that are actually available to be managed. There is a section later in this tutorial that describes how to discover what is manageable on the QMF bus.</p> <p>Proxy objects are obtained by calling the <em>Session.getObjects</em> function.</p> <p>To illustrate, we'll get a list of objects representing queues in the message broker itself.</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>qmf::Object::Vector objects; sessMgr.getObjects(objects, "queue"); </pre> </div></div> <p>We can also specify a specific broker when querying.</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>qmf::Broker* broker = sessMgr.addBroker("amqp://localhost:5672"); qmf::Object::Vector objects; sessMgr.getObjects(objects, "queue", broker); </pre> </div></div> <p><em>queues</em> is an array of proxy objects representing real queues on the message broker. A proxy object can be printed to display a description of the object.</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>for(unsigned int i = 0; i < objects.size(); i++) { std::string queueName = objects[i].attrString("name"); std::cout << "name: " << queueName << std::endl; qmf::Object obj = objects[i]; std::cout << "tostring: " << obj << std::endl; } name: qmfc-a3159ef6-17c5-461f-a27d-7c79fcc132fc tostring: org.apache.qpid.broker:queue[0-21-1-0-179] 0-0-1-0-1152921504606846979:qmfc-a3159ef6-17c5-461f-a27d-7c79fcc132fc </pre> </div></div> <h3><a name="QMFPythonConsoleTutorial-ViewingPropertiesandStatisticsofanObject"></a>Viewing Attributes of an Object</h3> <p>Let us now focus our attention on one of the queue objects.</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>qmf::Object obj = objects[i]; </pre> </div></div> <p>The attributes of an object are stored in a map.</p> <p>We can iterate through the attributes of an object:</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>qmf::Object::AttributeMap attributes = obj.getAttributes(); for(qmf::Object::AttributeMap::const_iterator vIter = attributes.begin(); vIter != attributes.end(); vIter++) { std::cout << "Attribute: " << vIter->first << " Value: " << vIter->second->str() << std::endl; } Attribute: arguments Value: {} Attribute: autoDelete Value: T Attribute: bindingCount Value: 4 Attribute: bindingCountHigh Value: 4 Attribute: bindingCountLow Value: 4 Attribute: byteDepth Value: 912 Attribute: bytePersistDequeues Value: 0 Attribute: bytePersistEnqueues Value: 0 Attribute: byteTotalDequeues Value: 30371 Attribute: byteTotalEnqueues Value: 31283 Attribute: byteTxnDequeues Value: 0 Attribute: byteTxnEnqueues Value: 0 Attribute: consumerCount Value: 1 Attribute: consumerCountHigh Value: 1 Attribute: consumerCountLow Value: 1 Attribute: durable Value: F Attribute: exclusive Value: T Attribute: messageLatencyAverage Value: 0 Attribute: messageLatencyMax Value: 0 Attribute: messageLatencyMin Value: 0 Attribute: messageLatencySamples Value: 0 Attribute: msgDepth Value: 3 Attribute: msgPersistDequeues Value: 0 Attribute: msgPersistEnqueues Value: 0 Attribute: msgTotalDequeues Value: 72 Attribute: msgTotalEnqueues Value: 75 Attribute: msgTxnDequeues Value: 0 Attribute: msgTxnEnqueues Value: 0 Attribute: name Value: qmfc-bfd3ec18-8222-488f-8c3d-221029145106 Attribute: unackedMessages Value: 0 Attribute: unackedMessagesHigh Value: 0 Attribute: unackedMessagesLow Value: 0 Attribute: vhostRef Value: 0-0-1-0-1152921504606846979 </pre> </div></div> <p>A more convenient way to access attributes is by using the attribute of the proxy object directly:</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>std::string name; name = obj.attrString("name"); std::cout << "Name: " << name << std::endl; bool autoDelete; autoDelete = obj.attrBool("autoDelete"); std::cout << "autoDelete: " << autoDelete << std::endl; Name: qmfc-e9d8f830-ac50-4377-b38c-7b0ffa1d86d2 autoDelete: 1 </pre> </div></div> <p>Statistics are accessed in the same way:</p> <div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> <pre>int msgDepth; msgDepth = obj.attrInt("msgDepth"); std::cout << "msgDepth: " << msgDepth << std::endl; msgDepth: 0 </pre> </div></div> <p>The proxy objects do not automatically track changes that occur on the real objects. For example, if the real queue enqueues more bytes, viewing the <em>byteTotalEnqueues</em> statistic will show the same number as it did the first time. To get updated data on a proxy object, query the <em>SessionManager</em> again.</p> </div> <!-- --> </div> <div class="footer"> Apache Qpid, Enterprise AMQP Messaging © 2004-2008 The Apache Software Foundation. (<a href="http://cwiki.apache.org/confluence/pages/editpage.action?pageId=108629">edit this page</a>) </div> </div></body></html> -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online. --------------------------------------------------------------------- Apache Qpid - AMQP Messaging Implementation Project: http://qpid.apache.org Use/Interact: mailto:dev-subscr...@qpid.apache.org