You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ro...@apache.org on 2017/05/24 14:58:43 UTC
[4/8] qpid-cpp git commit: QPID-7756: rename the book to better
reflect its content
http://git-wip-us.apache.org/repos/asf/qpid-cpp/blob/99dd7d38/docs/book/src/programming/Programming-In-Apache-Qpid.xml
----------------------------------------------------------------------
diff --git a/docs/book/src/programming/Programming-In-Apache-Qpid.xml b/docs/book/src/programming/Programming-In-Apache-Qpid.xml
deleted file mode 100644
index d13ec78..0000000
--- a/docs/book/src/programming/Programming-In-Apache-Qpid.xml
+++ /dev/null
@@ -1,4850 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<!--
-
-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.
-
--->
-
-<book id="client-api-tutorial">
- <title>Programming in Apache Qpid</title>
- <subtitle>Cross-Platform AMQP Messaging in Java JMS, .NET, C++, and Python</subtitle>
-
- <chapter>
- <title>Using the Qpid Messaging API</title>
-
- <para>The Qpid Messaging API is quite simple, consisting of only a
- handful of core classes.
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- A <firstterm>message</firstterm> consists of a standard set
- of fields (e.g. <literal>subject</literal>,
- <literal>reply-to</literal>), an application-defined set of
- properties, and message content (the main body of the
- message).
- </para>
- </listitem>
-
- <listitem>
- <para>
- A <firstterm>connection</firstterm> represents a network
- connection to a remote endpoint.
- </para>
- </listitem>
-
- <listitem>
- <para>
- A <firstterm>session</firstterm> provides a sequentially
- ordered context for sending and receiving
- <emphasis>messages</emphasis>. A session is obtained from a
- connection.
- </para>
- </listitem>
-
- <listitem>
- <para>
- A <firstterm>sender</firstterm> sends messages to a target
- using the <literal>sender.send</literal> method. A sender is
- obtained from a session for a given target address.
- </para>
- </listitem>
-
- <listitem>
- <para>
- A <firstterm>receiver</firstterm> receives messages from a
- source using the <literal>receiver.fetch</literal> method.
- A receiver is obtained from a session for a given source
- address.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The following sections show how to use these classes in a
- simple messaging program.
- </para>
-
- <section>
- <title>A Simple Messaging Program in C++</title>
-
- <para>The following C++ program shows how to create a connection,
- create a session, send messages using a sender, and receive
- messages using a receiver.</para>
-
- <example>
- <title>"Hello world!" in C++</title>
- <programlisting lang="c++"><![CDATA[
- #include <qpid/messaging/Connection.h>
- #include <qpid/messaging/Message.h>
- #include <qpid/messaging/Receiver.h>
- #include <qpid/messaging/Sender.h>
- #include <qpid/messaging/Session.h>
-
- #include <iostream>]]>
-
- using namespace qpid::messaging;
-
- int main(int argc, char** argv) {
- std::string broker = argc > 1 ? argv[1] : "localhost:5672";
- std::string address = argc > 2 ? argv[2] : "amq.topic";
- std::string connectionOptions = argc > 3 ? argv[3] : "";
-
- Connection connection(broker, connectionOptions);
- try {
- connection.open(); <co id="hello-cpp-open" linkends="callout-cpp-open"/>
- Session session = connection.createSession(); <co id="hello-cpp-session" linkends="callout-cpp-session"/>
-
- Receiver receiver = session.createReceiver(address); <co id="hello-cpp-receiver" linkends="callout-cpp-receiver"/>
- Sender sender = session.createSender(address); <co id="hello-cpp-sender" linkends="callout-cpp-sender"/>
-
- sender.send(Message("Hello world!"));
-
- Message message = receiver.fetch(Duration::SECOND * 1); <co id="hello-cpp-fetch" linkends="callout-cpp-fetch"/>
- <![CDATA[std::cout << message.getContent() << std::endl;]]>
- session.acknowledge(); <co id="hello-cpp-acknowledge" linkends="callout-cpp-acknowledge"/>
-
- connection.close(); <co id="hello-cpp-close" linkends="callout-cpp-close"/>
- return 0;
- } catch(const std::exception& error) {
- <![CDATA[std::cerr << error.what() << std::endl;]]>
- connection.close();
- return 1;
- }
- }</programlisting>
-
- <calloutlist>
- <callout id="callout-cpp-open" arearefs="hello-cpp-open">
- <para>Establishes the connection with the messaging broker.</para>
- </callout>
- <callout id="callout-cpp-session" arearefs="hello-cpp-session">
- <para>Creates a session object on which messages will be sent and received.</para>
- </callout>
- <callout id="callout-cpp-receiver" arearefs="hello-cpp-receiver">
- <para>Creates a receiver that receives messages from the given address.</para>
- </callout>
- <callout id="callout-cpp-sender" arearefs="hello-cpp-sender">
- <para>Creates a sender that sends to the given address.</para>
- </callout>
- <callout id="callout-cpp-fetch" arearefs="hello-cpp-fetch">
- <para>Receives the next message. The duration is optional, if omitted, will wait indefinitely for the next message.</para>
- </callout>
- <callout id="callout-cpp-acknowledge" arearefs="hello-cpp-acknowledge">
- <para>Acknowledges receipt of all fetched messages on the
- session. This informs the broker that the messages were
- transferred and processed by the client successfully.</para>
- </callout>
- <callout id="callout-cpp-close" arearefs="hello-cpp-close">
- <para>Closes the connection, all sessions managed by the connection, and all senders and receivers managed by each session.</para>
- </callout>
- </calloutlist>
- </example>
-
-
- </section>
-
- <section>
- <title>A Simple Messaging Program in Python</title>
-
- <para>The following Python program shows how to create a
- connection, create a session, send messages using a sender, and
- receive messages using a receiver.</para>
-
- <example>
- <title>"Hello world!" in Python</title>
- <programlisting lang="python"><![CDATA[
- import sys
- from qpid.messaging import *
-
- broker = "localhost:5672" if len(sys.argv)<2 else sys.argv[1]
- address = "amq.topic" if len(sys.argv)<3 else sys.argv[2]]]>
-
- connection = Connection(broker)
-
- try:
- connection.open() <co id="hello-python-open" linkends="callout-python-open"/>
- session = connection.session() <co id="hello-python-session" linkends="callout-python-session"/>
-
- sender = session.sender(address) <co id="hello-python-sender" linkends="callout-python-sender"/>
- receiver = session.receiver(address) <co id="hello-python-receiver" linkends="callout-python-receiver"/>
-
- sender.send(Message("Hello world!"));
-
- message = receiver.fetch(timeout=1) <co id="hello-python-fetch" linkends="callout-python-fetch"/>
- print message.content
- session.acknowledge() <co id="hello-python-acknowledge" linkends="callout-python-acknowledge"/>
-
- except MessagingError,m:
- print m
- finally:
- connection.close() <co id="hello-python-close" linkends="callout-python-close"/>
- </programlisting>
-
- <calloutlist>
- <callout id="callout-python-open" arearefs="hello-python-open">
- <para>Establishes the connection with the messaging broker.</para>
- </callout>
- <callout id="callout-python-session" arearefs="hello-python-session">
- <para>Creates a session object on which messages will be sent and received.</para>
- </callout>
- <callout id="callout-python-receiver" arearefs="hello-python-receiver">
- <para>Creates a receiver that receives messages from the given address.</para>
- </callout>
- <callout id="callout-python-sender" arearefs="hello-python-sender">
- <para>Creates a sender that sends to the given address.</para>
- </callout>
- <callout id="callout-python-fetch" arearefs="hello-python-fetch">
- <para>Receives the next message. The duration is optional, if omitted, will wait indefinitely for the next message.</para>
- </callout>
- <callout id="callout-python-acknowledge" arearefs="hello-python-acknowledge">
- <para>Acknowledges receipt of all fetched messages on
- the session. This informs the broker that the messages were
- transfered and processed by the client successfully.</para>
- </callout>
- <callout id="callout-python-close" arearefs="hello-python-close">
- <para>Closes the connection, all sessions managed by the connection, and all senders and receivers managed by each session.</para>
- </callout>
- </calloutlist>
-
- </example>
-
- </section>
-
-
-
-
- <section>
- <title>A Simple Messaging Program in .NET C#</title>
-
- <para>The following .NET C#
- <footnote>
- <para>
- The .NET binding for the Qpid C++ Messaging API
- applies to all .NET Framework managed code languages. C# was chosen
- for illustration purposes only.
- </para>
- </footnote>
- program shows how to create a connection,
- create a session, send messages using a sender, and receive
- messages using a receiver.
- </para>
-
- <example>
- <title>"Hello world!" in .NET C#</title>
- <programlisting lang="c++">
- using System;
- using Org.Apache.Qpid.Messaging; <co id="hello-csharp-using" linkends="callout-csharp-using"/>
-
- namespace Org.Apache.Qpid.Messaging {
- class Program {
- static void Main(string[] args) {
- String broker = args.Length > 0 ? args[0] : "localhost:5672";
- String address = args.Length > 1 ? args[1] : "amq.topic";
-
- Connection connection = null;
- try {
- connection = new Connection(broker);
- connection.Open(); <co id="hello-csharp-open" linkends="callout-csharp-open"/>
- Session session = connection.CreateSession(); <co id="hello-csharp-session" linkends="callout-csharp-session"/>
-
- Receiver receiver = session.CreateReceiver(address); <co id="hello-csharp-receiver" linkends="callout-csharp-receiver"/>
- Sender sender = session.CreateSender(address); <co id="hello-csharp-sender" linkends="callout-csharp-sender"/>
-
- sender.Send(new Message("Hello world!"));
-
- Message message = new Message();
- message = receiver.Fetch(DurationConstants.SECOND * 1); <co id="hello-csharp-fetch" linkends="callout-csharp-fetch"/>
- Console.WriteLine("{0}", message.GetContent());
- session.Acknowledge(); <co id="hello-csharp-acknowledge" linkends="callout-csharp-acknowledge"/>
-
- connection.Close(); <co id="hello-csharp-close" linkends="callout-csharp-close"/>
- } catch (Exception e) {
- Console.WriteLine("Exception {0}.", e);
- if (null != connection)
- connection.Close();
- }
- }
- }
- }
-
- </programlisting>
-
- <calloutlist>
- <callout id="callout-csharp-using" arearefs="hello-csharp-using">
- <para> Permits use of Org.Apache.Qpid.Messaging types and methods without explicit namespace qualification. Any .NET project must have a project reference to the assembly file <literal>Org.Apache.Qpid.Messaging.dll</literal> in order to obtain the definitions of the .NET Binding for Qpid Messaging namespace.</para>
- </callout>
- <callout id="callout-csharp-open" arearefs="hello-csharp-open">
- <para>Establishes the connection with the messaging broker.</para>
- </callout>
- <callout id="callout-csharp-session" arearefs="hello-csharp-session">
- <para>Creates a session object on which messages will be sent and received.</para>
- </callout>
- <callout id="callout-csharp-receiver" arearefs="hello-csharp-receiver">
- <para>Creates a receiver that receives messages from the given address.</para>
- </callout>
- <callout id="callout-csharp-sender" arearefs="hello-csharp-sender">
- <para>Creates a sender that sends to the given address.</para>
- </callout>
- <callout id="callout-csharp-fetch" arearefs="hello-csharp-fetch">
- <para>Receives the next message. The duration is optional, if omitted, will wait indefinitely for the next message.</para>
- </callout>
- <callout id="callout-csharp-acknowledge" arearefs="hello-csharp-acknowledge">
- <para>Acknowledges receipt of all fetched messages on the
- session. This informs the broker that the messages were
- transfered and processed by the client successfully.</para>
- </callout>
- <callout id="callout-csharp-close" arearefs="hello-csharp-close">
- <para>Closes the connection, all sessions managed by the connection, and all senders and receivers managed by each session.</para>
- </callout>
- </calloutlist>
- </example>
-
-
- </section>
-
-
-
-
-
-
- <section id="section-addresses">
- <title>Addresses</title>
-
- <para>An <firstterm>address</firstterm> is the name of a message
- target or message source.
-
- <footnote><para>In the programs we have just seen, we used
- <literal>amq.topic</literal> as the default address if none is
- passed in. This is the name of a standard exchange that always
- exists on an AMQP 0-10 messaging broker.</para></footnote>
-
- The methods that create senders and receivers require an
- address. The details of sending to a particular target or
- receiving from a particular source are then handled by the
- sender or receiver. A different target or source can be used
- simply by using a different address.
- </para>
-
- <para>An address resolves to a <firstterm>node</firstterm>. The
- Qpid Messaging API recognises two kinds of nodes,
- <firstterm>queues</firstterm> and <firstterm>topics</firstterm>
-
- <footnote><para>The terms <emphasis>queue</emphasis> and
- <emphasis>topic</emphasis> here were chosen to align with
- their meaning in JMS. These two addressing 'patterns',
- queue and topic, are sometimes refered as point-to-point
- and publish-subscribe. AMQP 0-10 has an exchange type
- called a <emphasis>topic exchange</emphasis>. When the term
- <emphasis>topic</emphasis> occurs alone, it refers to a
- Messaging API topic, not the topic
- exchange.</para></footnote>.
-
- A queue stores each message until it has been received and
- acknowledged, and only one receiver can receive a given message
-
- <footnote><para>There are exceptions to this rule; for instance,
- a receiver can use <literal>browse</literal> mode, which leaves
- messages on the queue for other receivers to
- read.</para></footnote>.
-
- A topic immediately delivers a message to all eligible
- receivers; if there are no eligible receivers, it discards the
- message. In the AMQP 0-10 implementation of the API,
-
- <footnote><para>The AMQP 0-10 implementation is the only one
- that currently exists.</para></footnote>
-
- queues map to AMQP queues, and topics map to AMQP exchanges.
-
- <footnote><para>In AMQP 0-10, messages are sent to
- exchanges, and read from queues. The Messaging API also
- allows a sender to send messages to a queue; internally,
- Qpid implements this by sending the message to the default
- exchange, with the name of the queue as the routing key. The
- Messaging API also allows a receiver to receive messages
- from a topic; internally, Qpid implements this by setting up
- a private subscription queue for the receiver and binding
- the subscription queue to the exchange that corresponds to
- the topic.</para></footnote>
- </para>
-
- <para>In the rest of this tutorial, we present many examples
- using two programs that take an address as a command line
- parameter. <command>spout</command> sends messages to the
- target address, <command>drain</command> receives messages from
- the source address. The source code is available in C++, Python, and
- .NET C# and can be found in the examples directory for each
- language. These programs can use any address string as a source
- or a destination, and have many command line options to
- configure behavior—use the <command>-h</command> option
- for documentation on these options.
-
- <footnote><para>Currently, the C++, Python, and .NET C#
- implementations of <command>drain</command> and
- <command>spout</command> have slightly different
- options. This tutorial uses the C++ implementation. The
- options will be reconciled in the near
- future.</para></footnote>
-
-
- The examples in this tutorial also use the
- <command>qpid-config</command> utility to configure AMQP 0-10
- queues and exchanges on a Qpid broker.
- </para>
-
-
- <example>
- <title>Queues</title>
-
- <para>Create a queue with <command>qpid-config</command>, send a message using
- <command>spout</command>, and read it using <command>drain</command>:</para>
-
- <screen>
- $ qpid-config add queue hello-world
- $ ./spout hello-world
- $ ./drain hello-world
-
- Message(properties={spout-id:c877e622-d57b-4df2-bf3e-6014c68da0ea:0}, content='')
- </screen>
-
- <para>The queue stored the message sent by <command>spout</command> and delivered
- it to <command>drain</command> when requested.</para>
-
- <para>Once the message has been delivered and and acknowledged
- by <command>drain</command>, it is no longer available on the queue. If we run
- <command>drain</command> one more time, no messages will be retrieved.</para>
-
- <screen>
- $ ./drain hello-world
- $
- </screen>
-
- </example>
-
- <example>
- <title>Topics</title>
-
- <para>This example is similar to the previous example, but it
- uses a topic instead of a queue.</para>
-
- <para>First, use <command>qpid-config</command> to remove the queue
- and create an exchange with the same name:</para>
-
- <screen>
- $ qpid-config del queue hello-world
- $ qpid-config add exchange topic hello-world
- </screen>
-
- <para>Now run <command>drain</command> and <command>spout</command> the same way we did in the previous example:</para>
-
- <screen>
- $ ./spout hello-world
- $ ./drain hello-world
- $
- </screen>
-
- <para>Topics deliver messages immediately to any interested
- receiver, and do not store messages. Because there were no
- receivers at the time <command>spout</command> sent the
- message, it was simply discarded. When we ran
- <command>drain</command>, there were no messages to
- receive.</para>
-
- <para>Now let's run <command>drain</command> first, using the
- <literal>-t</literal> option to specify a timeout in seconds.
- While <command>drain</command> is waiting for messages,
- run <command>spout</command> in another window.</para>
-
- <para><emphasis>First Window:</emphasis></para>
-
- <screen>
- $ ./drain -t 30 hello-word
- </screen>
-
-
- <para><emphasis>Second Window:</emphasis></para>
-
- <screen>
- $ ./spout hello-word
- </screen>
-
- <para>Once <command>spout</command> has sent a message, return
- to the first window to see the output from
- <command>drain</command>:</para>
-
- <screen>
- Message(properties={spout-id:7da2d27d-93e6-4803-8a61-536d87b8d93f:0}, content='')
- </screen>
-
- <para>You can run <command>drain</command> in several separate
- windows; each creates a subscription for the exchange, and
- each receives all messages sent to the exchange.</para>
-
- </example>
-
- <section>
- <title>Address Strings</title>
-
- <para>So far, our examples have used address strings that
- contain only the name of a node. An <firstterm>address
- string</firstterm> can also contain a
- <firstterm>subject</firstterm> and
- <firstterm>options</firstterm>.</para>
-
- <para>The syntax for an address string is:</para>
-
- <programlisting><![CDATA[
- address_string ::= <address> [ / <subject> ] [ ; <options> ]
- options ::= { <key> : <value>, ... }
- ]]></programlisting>
-
- <para>Addresses, subjects, and keys are strings. Values can
- be numbers, strings (with optional single or double quotes),
- maps, or lists. A complete BNF for address strings appears in
- <xref linkend="section-address-string-bnf"/>.</para>
-
-
- <para>So far, the address strings in this tutorial have only
- used simple names. The following sections show how to use
- subjects and options.</para>
-
- </section>
-
- <section>
- <title>Subjects</title>
-
-
- <para>Every message has a property called
- <firstterm>subject</firstterm>, which is analogous to the
- subject on an email message. If no subject is specified, the
- message's subject is null. For convenience, address strings
- also allow a subject. If a sender's address contains a
- subject, it is used as the default subject for the messages
- it sends.
-
- If a receiver's address contains a subject, it is used to
- select only messages that match the subject—the matching
- algorithm depends on the message source.
- </para>
-
- <para>
- In AMQP 0-10, each exchange type has its own matching
- algorithm. This is discussed in
- <xref linkend="section-amqp0-10-mapping"/>.
- </para>
-
- <note>
- <para>
- Currently, a receiver bound to a queue ignores subjects,
- receiving messages from the queue without filtering. Support
- for subject filtering on queues will be implemented soon.
- </para>
- </note>
-
-
- <example>
- <title>Using subjects</title>
-
- <para>In this example we show how subjects affect message
- flow.</para>
-
- <para>First, let's use <command>qpid-config</command> to create a topic exchange.</para>
-
- <screen>
- $ qpid-config add exchange topic news-service
- </screen>
-
- <para>Now we use drain to receive messages from <literal>news-service</literal> that match the subject <literal>sports</literal>.</para>
- <para><emphasis>First Window:</emphasis></para>
- <screen>
- $ ./drain -t 30 news-service/sports
- </screen>
-
- <para>In a second window, let's send messages to <literal>news-service</literal> using two different subjects:</para>
-
- <para><emphasis>Second Window:</emphasis></para>
- <screen>
- $ ./spout news-service/sports
- $ ./spout news-service/news
- </screen>
-
- <para>Now look at the first window, the message with the
- subject <literal>sports</literal> has been received, but not
- the message with the subject <literal>news</literal>:</para>
-
- <screen>
- Message(properties={qpid.subject:sports, spout-id:9441674e-a157-4780-a78e-f7ccea998291:0}, content='')
- </screen>
-
- <para>If you run <command>drain</command> in multiple
- windows using the same subject, all instances of
- <command>drain</command> receive the messages for that
- subject.</para>
- </example>
-
-
- <para>The AMQP exchange type we are using here,
- <literal>amq.topic</literal>, can also do more sophisticated
- matching.
-
- A sender's subject can contain multiple words separated by a
- <quote>.</quote> delimiter. For instance, in a news
- application, the sender might use subjects like
- <literal>usa.news</literal>, <literal>usa.weather</literal>,
- <literal>europe.news</literal>, or
- <literal>europe.weather</literal>.
-
- The receiver's subject can include wildcard characters—
- <quote>#</quote> matches one or more words in the message's
- subject, <quote>*</quote> matches a single word.
-
- For instance, if the subject in the source address is
- <literal>*.news</literal>, it matches messages with the
- subject <literal>europe.news</literal> or
- <literal>usa.news</literal>; if it is
- <literal>europe.#</literal>, it matches messages with subjects
- like <literal>europe.news</literal> or
- <literal>europe.pseudo.news</literal>.</para>
-
- <example>
- <title>Subjects with multi-word keys</title>
-
- <para>This example uses drain and spout to demonstrate the
- use of subjects with two-word keys.</para>
-
- <para>Let's use <command>drain</command> with the subject
- <literal>*.news</literal> to listen for messages in which
- the second word of the key is
- <literal>news</literal>.</para>
-
- <para><emphasis>First Window:</emphasis></para>
-
- <screen>
- $ ./drain -t 30 news-service/*.news
- </screen>
-
- <para>Now let's send messages using several different
- two-word keys:</para>
-
- <para><emphasis>Second Window:</emphasis></para>
-
- <screen>
- $ ./spout news-service/usa.news
- $ ./spout news-service/usa.sports
- $ ./spout news-service/europe.sports
- $ ./spout news-service/europe.news
- </screen>
-
- <para>In the first window, the messages with
- <literal>news</literal> in the second word of the key have
- been received:</para>
-
- <screen>
- Message(properties={qpid.subject:usa.news, spout-id:73fc8058-5af6-407c-9166-b49a9076097a:0}, content='')
- Message(properties={qpid.subject:europe.news, spout-id:f72815aa-7be4-4944-99fd-c64c9747a876:0}, content='')
- </screen>
-
-
- <para>Next, let's use <command>drain</command> with the
- subject <literal>#.news</literal> to match any sequence of
- words that ends with <literal>news</literal>.</para>
-
- <para><emphasis>First Window:</emphasis></para>
-
- <screen>
- $ ./drain -t 30 news-service/#.news
- </screen>
-
- <para>In the second window, let's send messages using a
- variety of different multi-word keys:</para>
-
- <para><emphasis>Second Window:</emphasis></para>
-
- <screen>
- $ ./spout news-service/news
- $ ./spout news-service/sports
- $ ./spout news-service/usa.news
- $ ./spout news-service/usa.sports
- $ ./spout news-service/usa.faux.news
- $ ./spout news-service/usa.faux.sports
- </screen>
-
- <para>In the first window, messages with
- <literal>news</literal> in the last word of the key have been
- received:</para>
-
- <screen>
- Message(properties={qpid.subject:news, spout-id:cbd42b0f-c87b-4088-8206-26d7627c9640:0}, content='')
- Message(properties={qpid.subject:usa.news, spout-id:234a78d7-daeb-4826-90e1-1c6540781eac:0}, content='')
- Message(properties={qpid.subject:usa.faux.news, spout-id:6029430a-cfcb-4700-8e9b-cbe4a81fca5f:0}, content='')
- </screen>
- </example>
-
- </section>
-
- <section>
- <title>Address String Options</title>
-
- <para>
- The options in an address string can contain additional
- information for the senders or receivers created for it,
- including:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Policies for assertions about the node to which an address
- refers.
- </para>
- <para>
- For instance, in the address string <literal>my-queue;
- {assert: always, node:{ type: queue }}</literal>, the node
- named <literal>my-queue</literal> must be a queue; if not,
- the address does not resolve to a node, and an exception
- is raised.
- </para>
- </listitem>
- <listitem>
- <para>
- Policies for automatically creating or deleting the node to which an address refers.
- </para>
- <para>
- For instance, in the address string <literal>xoxox ; {create: always}</literal>,
- the queue <literal>xoxox</literal> is created, if it does
- not exist, before the address is resolved.
- </para>
- </listitem>
- <listitem>
- <para>
- Extension points that can be used for sender/receiver configuration.
- </para>
- <para>
- For instance, if the address for a receiver is
- <literal>my-queue; {mode: browse}</literal>, the receiver
- works in <literal>browse</literal> mode, leaving messages
- on the queue so other receivers can receive them.
- </para>
- </listitem>
- <listitem>
- <para>
- Extension points providing more direct control over the underlying protocol.
- </para>
- <para>
- For instance, the <literal>x-bindings</literal> property
- allows greater control over the AMQP 0-10 binding process
- when an address is resolved.
- </para>
- </listitem>
- </itemizedlist>
-
-
- <para>
- Let's use some examples to show how these different kinds of
- address string options affect the behavior of senders and
- receives.
- </para>
-
- <section>
- <title>assert</title>
- <para>
- In this section, we use the <literal>assert</literal> option
- to ensure that the address resolves to a node of the required
- type.
- </para>
-
-
- <example>
- <title>Assertions on Nodes</title>
-
- <para>Let's use <command>qpid-config</command> to create a
- queue and a topic.</para>
-
- <screen>
- $ qpid-config add queue my-queue
- $ qpid-config add exchange topic my-topic
- </screen>
-
- <para>
- We can now use the address specified to drain to assert that it is
- of a particular type:
- </para>
-
- <screen>
- $ ./drain 'my-queue; {assert: always, node:{ type: queue }}'
- $ ./drain 'my-queue; {assert: always, node:{ type: topic }}'
- 2010-04-20 17:30:46 warning Exception received from broker: not-found: not-found: Exchange not found: my-queue (../../src/qpid/broker/ExchangeRegistry.cpp:92) [caused by 2 \x07:\x01]
- Exchange my-queue does not exist
- </screen>
-
- <para>
- The first attempt passed without error as my-queue is indeed a
- queue. The second attempt however failed; my-queue is not a
- topic.
- </para>
-
- <para>
- We can do the same thing for my-topic:
- </para>
-
- <screen>
- $ ./drain 'my-topic; {assert: always, node:{ type: topic }}'
- $ ./drain 'my-topic; {assert: always, node:{ type: queue }}'
- 2010-04-20 17:31:01 warning Exception received from broker: not-found: not-found: Queue not found: my-topic (../../src/qpid/broker/SessionAdapter.cpp:754) [caused by 1 \x08:\x01]
- Queue my-topic does not exist
- </screen>
- </example>
-
- <para>Now let's use the <literal>create</literal> option to
- create the queue <literal>xoxox</literal> if it does not already
- exist:</para>
-
- </section>
-
- <section>
- <title>create</title>
-
- <para>In previous examples, we created the queue before
- listening for messages on it. Using <literal>create:
- always</literal>, the queue is automatically created if it
- does not exist.</para>
-
- <example>
- <title>Creating a Queue Automatically</title>
-
- <para><emphasis>First Window:</emphasis></para>
- <screen>$ ./drain -t 30 "xoxox ; {create: always}"</screen>
-
-
- <para>Now we can send messages to this queue:</para>
-
- <para><emphasis>Second Window:</emphasis></para>
- <screen>$ ./spout "xoxox ; {create: always}"</screen>
-
- <para>Returning to the first window, we see that <command>drain</command> has received this message:</para>
-
- <screen>Message(properties={spout-id:1a1a3842-1a8b-4f88-8940-b4096e615a7d:0}, content='')</screen>
- </example>
- <para>The details of the node thus created can be controlled by further options within the node. See <xref linkend="table-node-properties"/> for details.</para>
- </section>
-
- <section>
- <title>browse</title>
- <para>Some options specify message transfer semantics; for
- instance, they may state whether messages should be consumed or
- read in browsing mode, or specify reliability
- characteristics. The following example uses the
- <literal>browse</literal> option to receive messages without
- removing them from a queue.</para>
-
- <example>
- <title>Browsing a Queue</title>
- <para>
- Let's use the browse mode to receive messages without
- removing them from the queue. First we send three messages to the
- queue:
- </para>
- <screen>
- $ ./spout my-queue --content one
- $ ./spout my-queue --content two
- $ ./spout my-queue --content three
- </screen>
-
- <para>Now we use drain to get those messages, using the browse option:</para>
- <screen>
- $ ./drain 'my-queue; {mode: browse}'
- Message(properties={spout-id:fbb93f30-0e82-4b6d-8c1d-be60eb132530:0}, content='one')
- Message(properties={spout-id:ab9e7c31-19b0-4455-8976-34abe83edc5f:0}, content='two')
- Message(properties={spout-id:ea75d64d-ea37-47f9-96a9-d38e01c97925:0}, content='three')
- </screen>
-
- <para>We can confirm the messages are still on the queue by repeating the drain:</para>
- <screen>
- $ ./drain 'my-queue; {mode: browse}'
- Message(properties={spout-id:fbb93f30-0e82-4b6d-8c1d-be60eb132530:0}, content='one')
- Message(properties={spout-id:ab9e7c31-19b0-4455-8976-34abe83edc5f:0}, content='two')
- Message(properties={spout-id:ea75d64d-ea37-47f9-96a9-d38e01c97925:0}, content='three')
- </screen>
- </example>
- </section>
-
- <section>
- <title>x-bindings</title>
-
- <para>Greater control over the AMQP 0-10 binding process can
- be achieved by including an <literal>x-bindings</literal>
- option in an address string.
-
- For instance, the XML Exchange is an AMQP 0-10 custom exchange
- provided by the Apache Qpid C++ broker. It allows messages to
- be filtered using XQuery; queries can address either message
- properties or XML content in the body of the message. The
- xquery is specified in the arguments field of the AMQP 0-10
- command. When using the messaging API an xquery can be
- specified in and address that resolves to an XML exchange by
- using the x-bindings property.</para>
-
-
- <para>An instance of the XML Exchange must be added before it
- can be used:</para>
-
- <programlisting>
- $ qpid-config add exchange xml xml
- </programlisting>
-
- <para>When using the XML Exchange, a receiver provides an
- XQuery as an x-binding argument. If the query contains a
- context item (a path starting with <quote>.</quote>), then it
- is applied to the content of the message, which must be
- well-formed XML. For instance, <literal>./weather</literal> is
- a valid XQuery, which matches any message in which the root
- element is named <literal>weather</literal>. Here is an
- address string that contains this query:</para>
-
- <programlisting><![CDATA[
- xml; {
- link: {
- x-bindings: [{exchange:xml, key:weather, arguments:{xquery:"./weather"} }]
- }
- }
- ]]></programlisting>
-
- <para>When using longer queries with <command>drain</command>,
- it is often useful to place the query in a file, and use
- <command>cat</command> in the command line. We do this in the
- following example.</para>
-
- <example>
- <title>Using the XML Exchange</title>
-
- <para>This example uses an x-binding that contains queries, which filter based on the content of XML messages. Here is an XQuery that we will use in this example:</para>
-
- <programlisting>
- <![CDATA[
- let $w := ./weather
- return $w/station = 'Raleigh-Durham International Airport (KRDU)'
- and $w/temperature_f > 50
- and $w/temperature_f - $w/dewpoint > 5
- and $w/wind_speed_mph > 7
- and $w/wind_speed_mph < 20 ]]>
- </programlisting>
-
- <para>We can specify this query in an x-binding to listen to messages that meet the criteria specified by the query:</para>
-
- <para><emphasis>First Window:</emphasis></para>
-
- <screen>
- $ ./drain -f "xml; {link:{x-bindings:[{key:'weather',
- arguments:{xquery:\"$(cat rdu.xquery )\"}}]}}"
- </screen>
-
- <para>In another window, let's create an XML message that meets the criteria in the query, and place it in the file <filename>rdu.xml</filename>:</para>
-
- <programlisting>
- <![CDATA[
- <weather>
- <station>Raleigh-Durham International Airport (KRDU)</station>
- <wind_speed_mph>16</wind_speed_mph>
- <temperature_f>70</temperature_f>
- <dewpoint>35</dewpoint>
- </weather>
- ]]></programlisting>
-
- <para>Now let's use <command>spout</command> to send this message to the XML exchange:</para>
-
- <para><emphasis>Second Window:</emphasis></para>
- <screen>
- spout --content "$(cat rdu.xml)" xml/weather
- </screen>
-
- <para>Returning to the first window, we see that the message has been received:</para>
-
- <screen><![CDATA[$ ./drain -f "xml; {link:{x-bindings:[{exchange:'xml', key:'weather', arguments:{xquery:\"$(cat rdu.xquery )\"}}]}}"
- Message(properties={qpid.subject:weather, spout-id:31c431de-593f-4bec-a3dd-29717bd945d3:0},
- content='<weather>
- <station>Raleigh-Durham International Airport (KRDU)</station>
- <wind_speed_mph>16</wind_speed_mph>
- <temperature_f>40</temperature_f>
- <dewpoint>35</dewpoint>
- </weather>') ]]>
- </screen>
- </example>
- </section>
-
- <!--
- <para>When sending data using <command>cat</command> to provide arguments to <command>spout</command>, you can use <command>sed</command> to change the values that are sent:</para>
-
-<screen>
-spout - -content "$(cat rdu.xml | sed -e 's/70/45/')" xml/weather
-</screen>
- -->
-
- <!--
- TODO: Add some reliability option examples
- -->
-
- <section>
- <title>Address String Options - Reference</title>
-
- <table pgwide="1">
- <title>Address String Options</title>
- <tgroup cols="3">
- <thead>
- <colspec colnum="1" colwidth="1*"/>
- <colspec colnum="2" colwidth="3*"/>
- <colspec colnum="3" colwidth="3*"/>
- <row>
- <entry>option</entry>
- <entry>value</entry>
- <entry>semantics</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- assert
- </entry>
- <entry>
- one of: always, never, sender or receiver
- </entry>
- <entry>
- Asserts that the properties specified in the node option
- match whatever the address resolves to. If they do not,
- resolution fails and an exception is raised. <!-- ###
- Which exception -->
- </entry>
- </row>
-
- <row>
- <entry>
- create
- </entry>
- <entry>
- one of: always, never, sender or receiver
- </entry>
- <entry>
- Creates the node to which an address refers if it does
- not exist. No error is raised if the node does
- exist. The details of the node may be specified in the
- node option.
- </entry>
- </row>
- <row>
- <entry>
- delete
- </entry>
- <entry>
- one of: always, never, sender or receiver
- </entry>
- <entry>
- Delete the node when the sender or receiver is closed.
- </entry>
- </row>
- <row>
- <entry>
- node
- </entry>
- <entry>
- A nested map containing the entries shown in <xref linkend="table-node-properties"/>.
- </entry>
- <entry>
- Specifies properties of the node to which the address
- refers. These are used in conjunction with the assert or
- create options.
- </entry>
- </row>
- <row>
- <entry>
- link
- </entry>
- <entry>
- A nested map containing the entries shown in <xref linkend="table-link-properties"/>.
- </entry>
- <entry>
- Used to control the establishment of a conceptual link
- from the client application to or from the target/source
- address.
- </entry>
- </row>
- <row>
- <entry>
- mode
- </entry>
- <entry>
- one of: browse, consume
- </entry>
- <entry>
- This option is only of relevance for source addresses
- that resolve to a queue. If browse is specified the
- messages delivered to the receiver are left on the queue
- rather than being removed. If consume is specified the
- normal behaviour applies; messages are removed from the
- queue once the client acknowledges their receipt.
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
-
- <table id="table-node-properties" pgwide="1">
- <title>Node Properties</title>
- <tgroup cols="3">
- <thead>
- <colspec colnum="1" colwidth="1*"/>
- <colspec colnum="2" colwidth="3*"/>
- <colspec colnum="3" colwidth="3*"/>
- <row>
- <entry>property</entry>
- <entry>value</entry>
- <entry>semantics</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- type
- </entry>
- <entry>
- topic, queue
- </entry>
- <entry>
- Indicates the type of the node.
- </entry>
- </row>
- <row>
- <entry>
- durable
- </entry>
- <entry>
- True, False
- </entry>
- <entry>
- Indicates whether the node survives a loss of
- volatile storage e.g. if the broker is restarted.
- </entry>
- </row>
- <row>
- <entry>
- x-declare
- </entry>
- <entry>
- A nested map whose values correspond to the valid fields
- on an AMQP 0-10 queue-declare or exchange-declare
- command.
- </entry>
- <entry>
- These values are used to fine tune the creation or
- assertion process. Note however that they are protocol
- specific.
- </entry>
- </row>
- <row>
- <entry>
- x-bindings
- </entry>
- <entry>
- A nested list in which each binding is represented by
- a map. The entries of the map for a binding contain
- the fields that describe an AMQP 0-10 binding. Here is
- the format for x-bindings:
-
- <programlisting><![CDATA[
- [
- {
- exchange: <exchange>,
- queue: <queue>,
- key: <key>,
- arguments: {
- <key_1>: <value_1>,
- ...,
- <key_n>: <value_n> }
- },
- ...
- ]
- ]]></programlisting>
- </entry>
- <entry>
- In conjunction with the create option, each of these
- bindings is established as the address is resolved. In
- conjunction with the assert option, the existence of
- each of these bindings is verified during
- resolution. Again, these are protocol specific.
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <table id="table-link-properties" pgwide="1">
- <title>Link Properties</title>
- <tgroup cols="3">
- <thead>
- <colspec colnum="1" colwidth="1*"/>
- <colspec colnum="2" colwidth="3*"/>
- <colspec colnum="3" colwidth="3*"/>
- <row>
- <entry>option</entry>
- <entry>value</entry>
- <entry>semantics</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- reliability
- </entry>
- <entry>
- one of: unreliable, at-least-once, at-most-once, exactly-once
- </entry>
- <entry>
- Reliability indicates the level of reliability that
- the sender or receiver. <literal>unreliable</literal>
- and <literal>at-most-once</literal> are currently
- treated as synonyms, and allow messages to be lost if
- a broker crashes or the connection to a broker is
- lost. <literal>at-least-once</literal> guarantees that
- a message is not lost, but duplicates may be
- received. <literal>exactly-once</literal> guarantees
- that a message is not lost, and is delivered precisely
- once. Currently only <literal>unreliable</literal>
- and <literal>at-least-once</literal> are supported.
- <footnote><para>If at-most-once is requested,
- unreliable will be used and for durable messages on
- durable queues there is the possibility that messages
- will be redelivered; if exactly-once is requested,
- at-least-once will be used and the application needs to
- be able to deal with duplicates.</para></footnote>
- </entry>
- </row>
- <row>
- <entry>
- durable
- </entry>
- <entry>
- True, False
- </entry>
- <entry>
- Indicates whether the link survives a loss of
- volatile storage e.g. if the broker is restarted.
- </entry>
- </row>
- <row>
- <entry>
- x-declare
- </entry>
- <entry>
- A nested map whose values correspond to the valid fields
- of an AMQP 0-10 queue-declare command.
- </entry>
- <entry>
- These values can be used to customise the subscription
- queue in the case of receiving from an exchange. Note
- however that they are protocol specific.
- </entry>
- </row>
- <row>
- <entry>
- x-subscribe
- </entry>
- <entry>
- A nested map whose values correspond to the valid fields
- of an AMQP 0-10 message-subscribe command.
- </entry>
- <entry>
- These values can be used to customise the subscription.
- </entry>
- </row>
- <row>
- <entry>
- x-bindings
- </entry>
- <entry>
- A nested list each of whose entries is a map that may
- contain fields (queue, exchange, key and arguments)
- describing an AMQP 0-10 binding.
- </entry>
- <entry>
- These bindings are established during resolution
- independent of the create option. They are considered
- logically part of the linking process rather than of
- node creation.
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- </section>
- </section>
-
- <section id="section-address-string-bnf">
- <title>Address String Grammar</title>
-
- <para>This section provides a formal grammar for address strings.</para>
-
- <formalpara>
- <title>Tokens</title>
- <para>The following regular expressions define the tokens used
- to parse address strings:</para></formalpara>
- <programlisting><![CDATA[
- LBRACE: \\{
- RBRACE: \\}
- LBRACK: \\[
- RBRACK: \\]
- COLON: :
- SEMI: ;
- SLASH: /
- COMMA: ,
- NUMBER: [+-]?[0-9]*\\.?[0-9]+
- ID: [a-zA-Z_](?:[a-zA-Z0-9_-]*[a-zA-Z0-9_])?
- STRING: "(?:[^\\\\"]|\\\\.)*"|\'(?:[^\\\\\']|\\\\.)*\'
- ESC: \\\\[^ux]|\\\\x[0-9a-fA-F][0-9a-fA-F]|\\\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]
- SYM: [.#*%@$^!+-]
- WSPACE: [ \\n\\r\\t]+
- ]]></programlisting>
-
- <formalpara>
- <title>Grammar</title>
- <para>The formal grammar for addresses is given below:</para>
- </formalpara>
-
- <programlisting><![CDATA[
- address := name [ SLASH subject ] [ ";" options ]
- name := ( part | quoted )+
- subject := ( part | quoted | SLASH )*
- quoted := STRING / ESC
- part := LBRACE / RBRACE / COLON / COMMA / NUMBER / ID / SYM
- options := map
- map := "{" ( keyval ( "," keyval )* )? "}"
- keyval "= ID ":" value
- value := NUMBER / STRING / ID / map / list
- list := "[" ( value ( "," value )* )? "]"
- ]]></programlisting>
-
-
- <formalpara>
- <title>Address String Options</title>
- <para>The address string options map supports the following parameters:</para>
- </formalpara>
-
- <programlisting><![CDATA[
- <name> [ / <subject> ] ; {
- create: always | sender | receiver | never,
- delete: always | sender | receiver | never,
- assert: always | sender | receiver | never,
- mode: browse | consume,
- node: {
- type: queue | topic,
- durable: True | False,
- x-declare: { ... <declare-overrides> ... },
- x-bindings: [<binding_1>, ... <binding_n>]
- },
- link: {
- name: <link-name>,
- durable: True | False,
- reliability: unreliable | at-most-once | at-least-once | exactly-once,
- x-declare: { ... <declare-overrides> ... },
- x-bindings: [<binding_1>, ... <binding_n>],
- x-subscribe: { ... <subscribe-overrides> ... }
- }
- }
- ]]></programlisting>
-
-
- <itemizedlist>
- <title>Create, Delete, and Assert Policies</title>
- <para>The create, delete, and assert policies specify who should
- perfom the associated action:</para>
- <listitem><para><emphasis>always</emphasis>: the action is performed by any messaging client</para></listitem>
- <listitem><para><emphasis>sender</emphasis>: the action is only performed by a sender</para></listitem>
- <listitem><para><emphasis>receiver</emphasis>: the action is only performed by a receiver</para></listitem>
- <listitem><para><emphasis>never</emphasis>: the action is never performed (this is the default)</para></listitem>
- </itemizedlist>
-
- <itemizedlist>
- <title>Node-Type</title>
- <para>The node-type is one of:</para>
- <listitem><para><emphasis>topic</emphasis>: in the AMQP 0-10
- mapping, a topic node defaults to the topic exchange, x-declare
- may be used to specify other exchange types</para></listitem>
- <listitem><para><emphasis>queue</emphasis>: this is the default node-type</para></listitem>
- </itemizedlist>
- </section>
-
-
- </section>
-
- <section id="replay">
- <title>Sender Capacity and Replay</title>
-
- <para>The send method of a sender has an optional second parameter
- that controls whether the send call is synchronous or not. A
- synchronous send call will block until the broker has confirmed
- receipt of the message. An asynchronous send call will return
- before the broker confirms receipt of the message, allowing for
- example further send calls to be made without waiting for a
- roundtrip to the broker for each message. This is desirable where
- increased throughput is important.</para>
-
- <para>The sender maintains a list of sent messages whose receipt
- has yet to be confirmed by the broker. The maximum number of such
- messages that it will hold is defined by the capacity of the
- sender, which can be set by the application. If an application
- tries to send with a sender whose capacity is already fully used
- up, the send call will block waiting for capacity regardless of
- the value of the sync flag.</para>
-
- <para>The sender can be queried for the available space (i.e. the
- unused capacity), and for the current count of unsettled messages
- (i.e. those held in the replay list pending confirmation by the
- server). When the unsettled count is zero, all messages on that
- sender have been successfully sent.</para>
-
- <para>If the connection fails and is transparently reconnected
- (see <xref linkend="connection-options"/> for details on how to control
- this feature), the unsettled messages for each sender over that
- connection will be re-transmitted. This provides a transparent
- level of reliability. This feature can be controlled through the
- link's reliability as defined in the address (see
- <xref linkend="table-link-properties"/>). At present only
- at-least-once guarantees are offered. </para>
- </section>
-
- <section id="prefetch">
- <title>Receiver Capacity (Prefetch)</title>
-
- <para>By default, a receiver requests the next message from the
- server in response to each fetch call, resulting in messages being
- sent to the receiver one at a time. As in the case of sending, it
- is often desirable to avoid this roundtrip for each message. This
- can be achieved by allowing the receiver
- to <firstterm>prefetch</firstterm> messages in anticipation of
- fetch calls being made. The receiver needs to be able to store
- these prefetched messages, the number it can hold is controlled by
- the receivers capacity.</para>
-
- </section>
-
- <section id="acknowledgements">
- <title>Acknowledging Received Messages</title>
-
- <para>Applications that receive messages should acknowledge their
- receipt by calling the session's acknowledge method. As in the
- case of sending messages, acknowledged transfer of messages to
- receivers provides at-least-once reliability, which means that the
- loss of the connection or a client crash does not result in lost
- messages; durable messages are not lost even if the broker is
- restarted.
-
- Some cases may not require this however and the reliability can be
- controlled through a link property in the address options (see
- <xref linkend="table-link-properties"/>).</para>
-
- <para>The acknowledge call acknowledges all messages received on
- the session (i.e. all message that have been returned from a fetch
- call on a receiver created on that session).</para>
-
- <para>The acknowledge call also support an optional parameter
- controlling whether the call is synchronous or not. A synchronous
- acknowledge will block until the server has confirmed that it has
- received the acknowledgement. In the asynchronous case, when the
- call returns there is not yet any guarantee that the server has
- received and processed the acknowledgement. The session may be
- queried for the number of unsettled acknowledgements; when that
- count is zero all acknowledgements made for received messages have
- been successful.</para>
-
- </section>
-
-
- <section>
- <title>Receiving Messages from Multiple Sources</title>
-
- <para>A receiver can only read from one source, but many
- programs need to be able to read messages from many sources. In
- the Qpid Messaging API, a program can ask a session for
- the <quote>next receiver</quote>; that is, the receiver that is
- responsible for the next available message. The following
- examples show how this is done in C++, Python, and .NET C#.
- </para>
-
- <para>Note that to use this pattern you must enable prefetching
- for each receiver of interest so that the broker will send
- messages before a fetch call is made. See
- <xref linkend="prefetch"/> for more on this.</para>
-
- <example>
- <title>Receiving Messages from Multiple Sources</title>
-
- <para>C++:</para>
-
- <programlisting><![CDATA[
- Receiver receiver1 = session.createReceiver(address1);
- receiver1.setCapacity(10);
- Receiver receiver2 = session.createReceiver(address2);
- receiver2.setCapacity(10);
-
- Message message = session.nextReceiver().fetch();
- std::cout << message.getContent() << std::endl;
- session.acknowledge(); // acknowledge message receipt
- ]]> </programlisting>
-
- <para>Python:</para>
- <programlisting><![CDATA[
- receiver1 = session.receiver(address1)
- receiver1.capacity = 10
- receiver2 = session.receiver(address)
- receiver2.capacity = 10
- message = session.next_receiver().fetch()
- print message.content
- session.acknowledge()
- ]]> </programlisting>
-
- <para>.NET C#:</para>
- <programlisting><![CDATA[
- Receiver receiver1 = session.CreateReceiver(address1);
- receiver1.Capacity = 10;
- Receiver receiver2 = session.CreateReceiver(address2);
- receiver2.Capacity = 10;
-
- Message message = new Message();
- message = session.NextReceiver().Fetch();
- Console.WriteLine("{0}", message.GetContent());
- session.Acknowledge();
- ]]> </programlisting>
-
- </example>
- </section>
-
- <section>
- <title>Transactions</title>
-
- <para>Sometimes it is useful to be able to group messages
- transfers - sent and/or received - on a session into atomic
- grouping. This can be done be creating the session as
- transactional. On a transactional session sent messages only
- become available at the target address on commit. Likewise any
- received and acknowledged messages are only discarded at their
- source on commit
-
- <footnote><para>Note that this currently is only true for
- messages received using a reliable mode
- e.g. at-least-once. Messages sent by a broker to a receiver in
- unreliable receiver will be discarded immediately regardless of
- transctionality.</para></footnote>
-
- .</para>
-
- <example>
- <title>Transactions</title>
- <para>C++:</para>
- <programlisting><![CDATA[
- Connection connection(broker);
- Session session = connection.createTransactionalSession();
- ...
- if (smellsOk())
- session.commit();
- else
- session.rollback();
- ]]></programlisting>
- <para>
- .NET C#:
- </para>
-
- <programlisting>
- Connection connection = new Connection(broker);
- Session session = connection.CreateTransactionalSession();
- ...
- if (smellsOk())
- session.Commit();
- else
- session.Rollback();
- </programlisting>
- <!--
- <para>Python</para>
- <programlisting><![CDATA[
- ### TODO
- ]]></programlisting>
- -->
- </example>
-
- </section>
-
- <section id="connections">
- <title>Connections</title>
-
- <para>
- Messaging connections are created by specifying a broker or a list of brokers, and
- an optional set of connection options. The constructor prototypes for Connections
- are:
- </para>
-
- <programlisting><![CDATA[
- Connection connection();
- Connection connection(const string url);
- Connection connection(const string url, const string& options);
- Connection connection(const string url, const Variant::Map& options);
- ]]></programlisting>
-
- <para>
- Messaging connection URLs specify only the network host address(es). Connection
- options are specified separately as an options string or map. This is different
- from JMS Connection URLs that combine the network address and connection properties
- in a single string.
- </para>
-
- <section id="connection-url">
- <title>Connection URLs</title>
- <para>
- Connection URLs describe the broker or set of brokers to which the connection
- is to attach. The format of the Connection URL is defined by AMQP 0.10
- Domain:connection.amqp-host-url.
- </para>
-
- <programlisting><![CDATA[
- amqp_url = "amqp:" prot_addr_list
- prot_addr_list = [prot_addr ","]* prot_addr
- prot_addr = tcp_prot_addr | tls_prot_addr
-
- tcp_prot_addr = tcp_id tcp_addr
- tcp_id = "tcp:" | ""
- tcp_addr = [host [":" port] ]
- host = <as per http://www.ietf.org/rfc/rfc3986.txt>
- port = number ]]></programlisting>
-
- <para>
- Examples of Messaging Connection URLs
- </para>
-
- <programlisting><![CDATA[
- localhost
- localhost:5672
- localhost:9999
- 192.168.1.2:5672
- mybroker.example.com:5672
- amqp:tcp:localhost:5672
- tcp:locahost:5672,localhost:5800
- ]]></programlisting>
-
- </section>
-
- <section id="connection-options">
- <title>Connection Options</title>
-
- <para>
- Aspects of the connections behaviour can be controlled through
- specifying connection options. For example, connections can be
- configured to automatically reconnect if the connection to a
- broker is lost.
- </para>
-
- <example>
- <title>Specifying Connection Options in C++, Python, and .NET</title>
-
- <para>In C++, these options can be set using <function>Connection::setOption()</function> or by passing in a set of options to the constructor. The options can be passed in as a map or in string form:</para>
-
-
- <para>or</para>
-
- <programlisting><![CDATA[
- Connection connection("localhost:5672");
- connection.setOption("reconnect", true);
- try {
- connection.open();
- !!! SNIP !!!
- ]]></programlisting>
-
- <para>In Python, these options can be set as attributes of the connection or using named arguments in
- the <function>Connection</function> constructor:</para>
-
- <programlisting><![CDATA[
- connection = Connection("localhost:5672", reconnect=True)
- try:
- connection.open()
- !!! SNIP !!!
- ]]></programlisting>
-
- <para>or</para>
-
- <programlisting><![CDATA[
- connection = Connection("localhost:5672")
- connection.reconnect = True
- try:
- connection.open()
- !!! SNIP !!!
- ]]></programlisting>
- <para>
- In .NET, these options can be set using <function>Connection.SetOption()</function> or by passing in a set of options to the constructor. The options can be passed in as a map or in string form:
- </para>
-
- <programlisting>
- Connection connection= new Connection("localhost:5672", "{reconnect: true}");
- try {
- connection.Open();
- !!! SNIP !!!
- </programlisting>
- <para>
- or
- </para>
-
- <programlisting>
- Connection connection = new Connection("localhost:5672");
- connection.SetOption("reconnect", true);
- try {
- connection.Open();
- !!! SNIP !!!
- </programlisting>
-
- <para>See the reference documentation for details in each language.</para>
- </example>
-
- <para>The following table lists the supported connection options.</para>
-
- <table pgwide="1">
- <title>Connection Options</title>
- <tgroup cols="3">
- <thead>
- <colspec colnum="1" colwidth="1*"/>
- <colspec colnum="2" colwidth="1*"/>
- <colspec colnum="3" colwidth="3*"/>
- <row>
- <entry>option name</entry>
- <entry>value type</entry>
- <entry>semantics</entry>
- </row>
- </thead>
- <tbody>
-
- <row>
- <entry>
- <literal>username</literal>
- </entry>
- <entry>
- string
- </entry>
- <entry>
- The username to use when authenticating to the broker.
- </entry>
- </row>
- <row>
- <entry>
- <literal>password</literal>
- </entry>
- <entry>
- string
- </entry>
- <entry>
- The password to use when authenticating to the broker.
- </entry>
- </row>
- <row>
- <entry>
- <literal>sasl_mechanisms</literal>
- </entry>
- <entry>
- string
- </entry>
- <entry>
- The specific SASL mechanisms to use with the python
- client when authenticating to the broker. The value
- is a space separated list.
- </entry>
- </row>
-
-
- <row>
- <entry>
- <literal>reconnect</literal>
- </entry>
- <entry>
- boolean
- </entry>
- <entry>
- Transparently reconnect if the connection is lost.
- </entry>
- </row>
- <row>
- <entry>
- <literal>reconnect_timeout</literal>
- </entry>
- <entry>
- integer
- </entry>
- <entry>
- Total number of seconds to continue reconnection attempts before giving up and raising an exception.
- </entry>
- </row>
- <row>
- <entry>
- <literal>reconnect_limit</literal>
- </entry>
- <entry>
- integer
- </entry>
- <entry>
- Maximum number of reconnection attempts before giving up and raising an exception.
- </entry>
- </row>
- <row>
- <entry>
- <literal>reconnect_interval_min</literal>
- </entry>
- <entry>
- integer representing time in seconds
- </entry>
- <entry>
- Minimum number of seconds between reconnection attempts. The first reconnection attempt is made immediately; if that fails, the first reconnection delay is set to the value of <literal>reconnect_interval_min</literal>; if that attempt fails, the reconnect interval increases exponentially until a reconnection attempt succeeds or <literal>reconnect_interval_max</literal> is reached.
- </entry>
- </row>
- <row>
- <entry>
- <literal>reconnect_interval_max</literal>
- </entry>
- <entry>
- integer representing time in seconds
- </entry>
- <entry>
- Maximum reconnect interval.
- </entry>
- </row>
- <row>
- <entry>
- <literal>reconnect_interval</literal>
- </entry>
- <entry>
- integer representing time in seconds
- </entry>
- <entry>
- Sets both <literal>reconnection_interval_min</literal> and <literal>reconnection_interval_max</literal> to the same value.
- </entry>
- </row>
-
- <row>
- <entry>
- <literal>heartbeat</literal>
- </entry>
- <entry>
- integer representing time in seconds
- </entry>
- <entry>
- Requests that heartbeats be sent every N seconds. If two
- successive heartbeats are missed the connection is
- considered to be lost.
- </entry>
- </row>
- <row>
- <entry>
- <literal>transport</literal>
- </entry>
- <entry>
- string
- </entry>
- <entry>
- Sets the underlying transport protocol used. The default option is 'tcp'. To enable ssl, set to 'ssl'. The C++ client additionally supports 'rdma'.
- </entry>
- </row>
- <row>
- <entry>
- <literal>tcp-nodelay</literal>
- </entry>
- <entry>
- boolean
- </entry>
- <entry>
- Set tcp no-delay, i.e. disable Nagle algorithm. [C++ only]
- </entry>
- </row>
- <row>
- <entry>
- <literal>protocol</literal>
- </entry>
- <entry>
- string
- </entry>
- <entry>
- Sets the application protocol used. The default option is 'amqp0-10'. To enable AMQP 1.0, set to 'amqp1.0'.
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- </section>
- </section>
-
- <section id="section-Maps">
- <title>Maps and Lists in Message Content</title>
-
- <para>Many messaging applications need to exchange data across
- languages and platforms, using the native datatypes of each
- programming language.</para>
-
- <para>The Qpid Messaging API supports <classname>map</classname> and <classname>list</classname> in message content.
-
- <footnote><para>Unlike JMS, there is not a specific message type for
- map messages.</para></footnote>
-
- <footnote>
- <para>
- Note that the Qpid JMS client supports MapMessages whose values can be nested maps or lists. This is not standard JMS behaviour.
- </para>
- </footnote>
- Specific language support for <classname>map</classname> and <classname>list</classname> objects are shown in the following table.
- </para>
- <table id="tabl-Programming_in_Apache_Qpid-Qpid_Maps_in_Message_Content">
- <title>Map and List Representation in Supported Languages</title>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>Language</entry>
- <entry>map</entry>
- <entry>list</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>Python</entry>
- <entry><classname>dict</classname></entry>
- <entry><classname>list</classname></entry>
- </row>
- <row>
- <entry>C++</entry>
- <entry><classname>Variant::Map</classname></entry>
- <entry><classname>Variant::List</classname></entry>
- </row>
- <row>
- <entry>Java</entry>
- <entry><classname>MapMessage</classname></entry>
- <entry><classname> </classname></entry>
- </row>
- <row>
- <entry>.NET</entry>
- <entry><classname>Dictionary<string, object></classname></entry>
- <entry><classname>Collection<object></classname></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>
- In all languages, messages are encoded using AMQP's portable datatypes.
- </para>
-
- <tip>
- <para>Because of the differences in type systems among
- languages, the simplest way to provide portable messages is to
- rely on maps, lists, strings, 64 bit signed integers, and
- doubles for messages that need to be exchanged across languages
- and platforms.</para>
- </tip>
-
- <section id="section-Python-Maps">
- <title>Qpid Maps and Lists in Python</title>
-
- <para>In Python, Qpid supports the <classname>dict</classname> and <classname>list</classname> types directly in message content. The following code shows how to send these structures in a message:</para>
-
- <example>
- <title>Sending Qpid Maps and Lists in Python</title>
- <programlisting><![CDATA[
- from qpid.messaging import *
- # !!! SNIP !!!
-
- content = {'Id' : 987654321, 'name' : 'Widget', 'percent' : 0.99}
- content['colours'] = ['red', 'green', 'white']
- content['dimensions'] = {'length' : 10.2, 'width' : 5.1,'depth' : 2.0};
- content['parts'] = [ [1,2,5], [8,2,5] ]
- content['specs'] = {'colors' : content['colours'],
- 'dimensions' : content['dimensions'],
- 'parts' : content['parts'] }
- message = Message(content=content)
- sender.send(message)
- ]]> </programlisting>
- </example>
-
-
- <para>The following table shows the datatypes that can be sent in a Python map message,
- and the corresponding datatypes that will be received by clients in Java or C++.</para>
-
-
- <table id="table-Python-Maps" >
- <title>Python Datatypes in Maps</title>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>Python Datatype</entry>
- <entry>→ C++</entry>
- <entry>→ Java</entry>
- </row>
- </thead>
- <tbody>
- <row><entry>bool</entry><entry>bool</entry><entry>boolean</entry></row>
- <row><entry>int</entry><entry>int64</entry><entry>long</entry></row>
- <row><entry>long</entry><entry>int64</entry><entry>long</entry></row>
- <row><entry>float</entry><entry>double</entry><entry>double</entry></row>
- <row><entry>unicode</entry><entry>string</entry><entry>java.lang.String</entry></row>
- <row><entry>uuid</entry><entry>qpid::types::Uuid</entry><entry>java.util.UUID</entry></row>
- <row><entry>dict</entry><entry>Variant::Map</entry><entry>java.util.Map</entry></row>
- <row><entry>list</entry><entry>Variant::List</entry><entry>java.util.List</entry></row>
- </tbody>
- </tgroup>
- </table>
-
- </section>
-
-
-
-
- <section id="section-cpp-Maps">
- <title>Qpid Maps and Lists in C++</title>
-
-
- <para>In C++, Qpid defines the the
- <classname>Variant::Map</classname> and
- <classname>Variant::List</classname> types, which can be
- encoded into message content. The following code shows how to
- send these structures in a message:</para>
-
- <example>
- <title>Sending Qpid Maps and Lists in C++</title>
- <programlisting><![CDATA[
- using namespace qpid::types;
-
- // !!! SNIP !!!
-
- Message message;
- Variant::Map content;
- content["id"] = 987654321;
- content["name"] = "Widget";
- content["percent"] = 0.99;
- Variant::List colours;
- colours.push_back(Variant("red"));
- colours.push_back(Variant("green"));
- colours.push_back(Variant("white"));
- content["colours"] = colours;
-
- Variant::Map dimensions;
- dimensions["length"] = 10.2;
- dimensions["width"] = 5.1;
- dimensions["depth"] = 2.0;
- content["dimensions"]= dimensions;
-
- Variant::List part1;
- part1.push_back(Variant(1));
- part1.push_back(Variant(2));
- part1.push_back(Variant(5));
-
- Variant::List part2;
- part2.push_back(Variant(8));
- part2.push_back(Variant(2));
- part2.push_back(Variant(5));
-
- Variant::List parts;
- parts.push_back(part1);
- parts.push_back(part2);
- content["parts"]= parts;
-
- Variant::Map specs;
- specs["colours"] = colours;
- specs["dimensions"] = dimensions;
- specs["parts"] = parts;
- content["specs"] = specs;
-
- encode(content, message);
- sender.send(message, true);
- ]]> </programlisting>
- </example>
-
- <para>The following table shows the datatypes that can be sent
- in a C++ map message, and the corresponding datatypes that
- will be received by clients in Java and Python.</para>
-
- <table id="table-cpp-Maps">
- <title>C++ Datatypes in Maps</title>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>C++ Datatype</entry>
- <entry>→ Python</entry>
- <entry>→ Java</entry>
- </row>
- </thead>
- <tbody>
- <row><entry>bool</entry><entry>bool</entry><entry>boolean</entry></row>
- <row><entry>uint16</entry><entry>int | long</entry><entry>short</entry></row>
- <row><entry>uint32</entry><entry>int | long</entry><entry>int</entry></row>
- <row><entry>uint64</entry><entry>int | long</entry><entry>long</entry></row>
- <row><entry>int16</entry><entry>int | long</entry><entry>short</entry></row>
- <row><entry>int32</entry><entry>int | long</entry><entry>int</entry></row>
- <row><entry>int64</entry><entry>int | long</entry><entry>long</entry></row>
- <row><entry>float</entry><entry>float</entry><entry>float</entry></row>
- <row><entry>double</entry><entry>float</entry><entry>double</entry></row>
- <row><entry>string</entry><entry>unicode</entry><entry>java.lang.String</entry></row>
- <row><entry>qpid::types::Uuid</entry><entry>uuid</entry><entry>java.util.UUID</entry></row>
- <row><entry>Variant::Map</entry><entry>dict</entry><entry>java.util.Map</entry></row>
- <row><entry>Variant::List</entry><entry>list</entry><entry>java.util.List</entry></row>
- </tbody>
- </tgroup>
- </table>
- </section>
-
- <section id="section-dotnet-Maps">
- <title>Qpid Maps and Lists in .NET</title>
-
-
- <para>
- The .NET binding for the Qpid Messaging API binds .NET managed data types
- to C++ <classname>Variant</classname> data types. The following code shows how to
- send Map and List structures in a message:
- </para>
-
- <example>
- <?dbfo keep-together="auto" ?>
- <title>Sending Qpid Maps and Lists in .NET C#</title>
- <programlisting><![CDATA[
- using System;
- using Org.Apache.Qpid.Messaging;
-
- // !!! SNIP !!!
-
- Dictionary<string, object> content = new Dictionary<string, object>();
- Dictionary<string, object> subMap = new Dictionary<string, object>();
- Collection<object> colors = new Collection<object>();
-
- // add simple types
- content["id"] = 987654321;
- content["name"] = "Widget";
- content["percent"] = 0.99;
-
- // add nested amqp/map
- subMap["name"] = "Smith";
- subMap["number"] = 354;
- content["nestedMap"] = subMap;
-
- // add an amqp/list
- colors.Add("red");
- colors.Add("green");
- colors.Add("white");
- content["colorsList"] = colors;
-
- // add one of each supported amqp data type
- bool mybool = true;
- content["mybool"] = mybool;
-
- byte mybyte = 4;
- content["mybyte"] = mybyte;
-
- UInt16 myUInt16 = 5;
- content["myUInt16"] = myUInt16;
-
- UInt32 myUInt32 = 6;
- content["myUInt32"] = myUInt32;
-
- UInt64 myUInt64 = 7;
- content["myUInt64"] = myUInt64;
-
- char mychar = 'h';
- content["mychar"] = mychar;
-
- Int16 myInt16 = 9;
- content["myInt16"] = myInt16;
-
- Int32 myInt32 = 10;
- content["myInt32"] = myInt32;
-
- Int64 myInt64 = 11;
- content["myInt64"] = myInt64;
-
- Single mySingle = (Single)12.12;
- content["mySingle"] = mySingle;
-
- Double myDouble = 13.13;
- content["myDouble"] = myDouble;
-
- Guid myGuid = new Guid("000102030405060708090a0b0c0d0e0f");
- content["myGuid"] = myGuid;
-
- Message message = new Message(content);
- Send(message, true);
- ]]> </programlisting>
- </example>
-
- <para>
- The following table shows the mapping between datatypes in .NET and C++.
- </para>
-
- <table id="table-dotnet-Maps">
- <title>Datatype Mapping between C++ and .NET binding</title>
- <tgroup cols="2">
- <thead>
- <row>
- <entry>C++ Datatype</entry>
- <entry>→ .NET binding</entry>
- </row>
- </thead>
- <tbody>
- <row><entry>void</entry><entry>nullptr</entry></row>
- <row><entry>bool</entry><entry>bool</entry></row>
- <row><entry>uint8</entry><entry>byte</entry></row>
- <row><entry>uint16</entry><entry>UInt16</entry></row>
- <row><entry>uint32</entry><entry>UInt32</entry></row>
- <row><entry>uint64</entry><entry>UInt64</entry></row>
- <row><entry>uint8</entry><entry>char</entry></row>
- <row><entry>int16</entry><entry>Int16</entry></row>
- <row><entry>int32</entry><entry>Int32</entry></row>
- <row><entry>int64</entry><entry>Int64</entry></row>
- <row><entry>float</entry><entry>Single</entry></row>
- <row><entry>double</entry><entry>Double</entry></row>
- <row><entry>string</entry><entry>string
- <footnote id="callout-dotnet-string">
- <para>Strings are currently interpreted only with UTF-8 encoding.</para>
- </footnote></entry></row>
- <row><entry>qpid::types::Uuid</entry><entry>Guid</entry></row>
- <row><entry>Variant::Map</entry><entry><![CDATA[Dictionary<string, object>]]>
- <footnoteref linkend="callout-dotnet-string"/></entry></row>
- <row><entry>Variant::List</entry><entry><![CDATA[Collection<object>]]>
- <footnoteref linkend="callout-dotnet-string"/></entry></row>
- </tbody>
- </tgroup>
- </table>
-
-
- </section>
-
-
- </section>
-
- <section>
- <title>The Request / Response Pattern</title>
- <para>Request / Response applications use the reply-to property,
- described in <xref
- linkend="table-amqp0-10-message-properties"/>, to allow a server
- to respond to the client that sent a message. A server sets up a
- service queue, with a name known to clients. A client creates a
- private queue for the server's response, creates a message for a
- request, sets the request's reply-to property to the address of
- the client's response queue, and sends the request to the
- service queue. The server sends the response to the address
- specified in the request's reply-to property.
- </para>
- <example>
- <title>Request / Response Applications in C++</title>
-
- <para>This example shows the C++ code for a client and server
- that use the request / response pattern.</para>
-
- <para>The server creates a service queue and waits for a
- message to arrive. If it receives a message, it sends a
- message back to the sender.</para>
-
- <programlisting><![CDATA[Receiver receiver = session.createReceiver("service_queue; {create: always}");
-
- Message request = receiver.fetch();
- const Address& address = request.getReplyTo(); // Get "reply-to" from request ...
- if (address) {
- Sender sender = session.createSender(address); // ... send response to "reply-to"
- Message response("pong!");
- sender.send(response);
- session.acknowledge();
- }
- ]]></programlisting>
-
- <para>The client creates a sender for the service queue, and
- also creates a response queue that is deleted when the
- client closes the receiver for the response queue. In the C++
- client, if the address starts with the character
- <literal>#</literal>, it is given a unique name.</para>
-
- <programlisting><![CDATA[
- Sender sender = session.createSender("service_queue");
-
- Address responseQueue("#response-queue; {create:always, delete:always}");
- Receiver receiver = session.createReceiver(responseQueue);
-
- Message request;
- request.setReplyTo(responseQueue);
- request.setContent("ping");
- sender.send(request);
- Message response = receiver.fetch();
- std::cout << request.getContent() << " -> " << response.getContent() << std::endl;
- ]]> </programlisting>
-
- <para>The client sends the string <literal>ping</literal> to
- the server. The server sends the response
- <literal>pong</literal> back to the same client, using the
- <varname>replyTo</varname> property.</para>
-
- </example>
- <!--
- <example>
- <title>Request / Response Applications in Python</title>
- <programlisting>### TODO</programlisting>
- </example>
- -->
- </section>
-
-
- <section>
- <title>Performance Tips</title>
-
- <itemizedlist>
- <listitem>
- <para>Consider prefetching messages for receivers (see
- <xref linkend="prefetch"/>). This helps eliminate roundtrips
- and increases throughput. Prefetch is disabled by default,
- and enabling it is the most effective means of improving
- throughput of received messages.</para>
- </listitem>
- <listitem>
- <para>Send messages asynchronously. Again, this helps
- eliminate roundtrips and increases throughput. The C++ and
- .NET clients send asynchronously by default, however the
- python client defaults to synchronous sends. </para>
- </listitem>
- <listitem>
- <para>Acknowledge messages in batches (see
- <xref linkend="acknowledgements"/>). Rather than
- acknowledging each message individually, consider issuing
- acknowledgements after n messages and/or after a particular
- duration has elapsed.</para>
- </listitem>
- <listitem>
- <para>Tune the sender capacity (see
- <xref linkend="replay"/>). If the capacity is too low the
- sender may block waiting for the broker to confirm receipt
- of messages, before it can free up more capacity.</para>
- </listitem>
- <listitem>
- <para>If you are setting a reply-to address on messages
- being sent by the c++ client, make sure the address type is
- set to either queue or topic as appropriate. This avoids the
- client having to determine which type of node is being
- refered to, which is required when hanling reply-to in AMQP
- 0-10. </para>
- </listitem>
- <listitem>
- <para>For latency sensitive applications, setting tcp-nodelay
- on qpidd and on client connections can help reduce the
- latency.</para>
- </listitem>
- </itemizedlist>
- </section>
-
- <section>
- <title>Cluster Failover</title>
-
- <para>The messaging broker can be run in clustering mode, which provides high reliability through replicating state between brokers in the cluster. If one broker in a cluster fails, clients can choose another broker in the cluster and continue their work. Each broker in the cluster also advertises the addresses of all known brokers
-
- <footnote><para>This is done via the amq.failover exchange in AMQP 0-10</para></footnote>
-
- . A client can use this information to dynamically keep the list of reconnection urls up to date.</para>
-
- <para>In C++, the <classname>FailoverUpdates</classname> class provides this functionality:</para>
-
- <example>
- <title>Tracking cluster membership</title>
-
- <para>In C++:</para>
-
- <programlisting><![CDATA[
- #include <qpid/messaging/FailoverUpdates.h>
- ...
- Connection connection("localhost:5672");
- connection.setOption("reconnect", true);
- try {
- connection.open();
- std::auto_ptr<FailoverUpdates> updates(new FailoverUpdates(connection));
- ]]>
- </programlisting>
-
- <para>In python:</para>
-
- <programlisting><![CDATA[
- import qpid.messaging.util
- ...
- connection = Connection("localhost:5672")
- connection.reconnect = True
- try:
- connection.open()
- auto_fetch_reconnect_urls(connection)
- ]]>
- </programlisting>
- <para>
- In .NET C#:
- </para>
-
- <programlisting>
- using Org.Apache.Qpid.Messaging;
- ...
- connection = new Connection("localhost:5672");
- connection.SetOption("reconnect", true);
- try {
- connection.Open();
- FailoverUpdates failover = new FailoverUpdates(connection);
-
- </programlisting>
-
-
- </example>
- </section>
-
-
-
- <section>
- <title>Logging</title>
-
- <para>To simplify debugging, Qpid provides a logging facility
- that prints out messaging events.</para>
-
- <section>
- <title>Logging in C++</title>
- <para>
- The Qpidd broker and C++ clients can both use environment variables to enable logging. Linux and Windows systems use the same named environment variables and values.
- </para>
- <para>Use QPID_LOG_ENABLE to set the level of logging you are interested in (trace, debug, info, notice, warning, error, or critical):
- </para>
-
- <screen>
- export QPID_LOG_ENABLE="warning+"
- </screen>
- <para>
- The Qpidd broker and C++ clients use QPID_LOG_OUTPUT to determine where logging output should be sent. This is either a file name or the special values stderr, stdout, or syslog:
- </para>
-
- <screen>
- export QPID_LOG_TO_FILE="/tmp/myclient.out"
- </screen>
-
- <para>
- From a Windows command prompt, use the following command format to set the environment variables:
- </para>
-
- <screen>
- set QPID_LOG_ENABLE=warning+
- set QPID_LOG_TO_FILE=D:\tmp\myclient.out
- </screen>
- </section>
-
- <section>
- <title>Logging in Python</title>
- <para>
- The Python client library supports logging using the standard Python logging module. The easiest way to do logging is to use the <command>basicConfig()</command>, which reports all warnings and errors:
- </para>
-
- <programlisting>from logging import basicConfig
- basicConfig()
- </programlisting>
- <para>
- Qpidd also provides a convenience method that makes it easy to specify the level of logging desired. For instance, the following code enables logging at the <command>DEBUG</command> level:
- </para>
-
- <programlisting>from qpid.log import enable, DEBUG
- enable("qpid.messaging.io", DEBUG)
- </programlisting>
- <para>
- For more information on Python logging, see <ulink url="http://docs.python.org/lib/node425.html">http://docs.python.org/lib/node425.html</ulink>. For more information on Qpid logging, use <command>$ pydoc qpid.log</command>.
- </para>
- </section>
- </section>
-
-
-
- <section id="section-amqp0-10-mapping">
- <title>The AMQP 0-10 mapping</title>
-
- <para>
- This section describes the AMQP 0-10 mapping for the Qpid
- Messaging API.
- </para>
- <para>
- The interaction with the broker triggered by creating a sender
- or receiver depends on what the specified address resolves
- to. Where the node type is not specified in the address, the
- client queries the broker to determine whether it refers to a
- queue or an exchange.
- </para>
- <para>
- When sending to a queue, the queue's name is set as the
- routing key and the message is transfered to the default (or
- nameless) exchange. When sending to an exchange, the message
- is transfered to that exchange and the routing key is set to
- the message subject if one is specified. A default subject may
- be specified in the target address. The subject may also be
- set on each message individually to override the default if
- required. In each case any specified subject is also added as
- a qpid.subject entry in the application-headers field of the
- message-properties.
- </para>
- <para>
- When receiving from a queue, any subject in the source address
- is currently ignored. The client sends a message-subscribe
- request for the queue in question. The accept-mode is
- determined by the reliability option in the link properties;
- for unreliable links the accept-mode is none, for reliable
- links it is explicit. The default for a queue is reliable. The
- acquire-mode is determined by the value of the mode option. If
- the mode is set to browse the acquire mode is not-acquired,
- otherwise it is set to pre-acquired. The exclusive and
- arguments fields in the message-subscribe command can be
- controlled using the x-subscribe map.
- </para>
- <para>
- When receiving from an exchange, the client creates a
- subscription queue and binds that to the exchange. The
- subscription queue's arguments can be specified using the
- x-declare map within the link properties. The reliability
- option determines most of the other parameters. If the
- reliability is set to unreliable then an auto-deleted,
- exclusive queue is used meaning that if the client or
- connection fails messages may be lost. For exactly-once the
- queue is not set to be auto-deleted. The durability of the
- subscription queue is determined by the durable option in the
- link properties. The binding process depends on the type of
- the exchange the source address resolves to.
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- For a topic exchange, if no subject is specified and no
- x-bindings are defined for the link, the subscription
- queue is bound using a wildcard matching any routing key
- (thus satisfying the expectation that any message sent to
- that address will be received from it). If a subject is
- specified in the source address however, it is used for
- the binding key (this means that the subject in the source
- address may be a binding pattern including wildcards).
- </para>
- </listitem>
- <listitem>
- <para>
- For a fanout exchange the binding key is irrelevant to
- matching. A receiver created from a source address that
- resolves to a fanout exchange receives all messages
- sent to that exchange regardless of any subject the source
- address may contain. An x-bindings element in the link
- properties should be used if there is any need to set the
- arguments to the bind.
- </para>
- </listitem>
- <listitem>
- <para>
- For a direct exchange, the subject is used as the binding
- key. If no subject is specified an empty string is used as
- the binding key.
- </para>
- </listitem>
- <listi
<TRUNCATED>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org