| <?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> |
| <listitem> |
| <para> |
| For a headers exchange, if no subject is specified the |
| binding arguments simply contain an x-match entry and no |
| other entries, causing all messages to match. If a subject |
| is specified then the binding arguments contain an x-match |
| entry set to all and an entry for qpid.subject whose value |
| is the subject in the source address (this means the |
| subject in the source address must match the message |
| subject exactly). For more control the x-bindings element |
| in the link properties must be used. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| For the XML exchange,<footnote><para>Note that the XML |
| exchange is not a standard AMQP exchange type. It is a |
| Qpid extension and is currently only supported by the C++ |
| broker.</para></footnote> if a subject is specified it is |
| used as the binding key and an XQuery is defined that |
| matches any message with that value for |
| qpid.subject. Again this means that only messages whose |
| subject exactly match that specified in the source address |
| are received. If no subject is specified then the empty |
| string is used as the binding key with an xquery that will |
| match any message (this means that only messages with an |
| empty string as the routing key will be received). For more |
| control the x-bindings element in the link properties must |
| be used. A source address that resolves to the XML |
| exchange must contain either a subject or an x-bindings |
| element in the link properties as there is no way at |
| present to receive any message regardless of routing key. |
| </para> |
| </listitem> |
| </itemizedlist> |
| |
| <para> |
| If an x-bindings list is present in the link options a binding |
| is created for each element within that list. Each element is |
| a nested map that may contain values named queue, exchange, |
| key or arguments. If the queue value is absent the queue name |
| the address resolves to is implied. If the exchange value is |
| absent the exchange name the address resolves to is implied. |
| </para> |
| |
| <para>The following table shows how Qpid Messaging API message |
| properties are mapped to AMQP 0-10 message properties and |
| delivery properties. In this table <varname>msg</varname> |
| refers to the Message class defined in the Qpid Messaging API, |
| <varname>mp</varname> refers to an AMQP 0-10 |
| <varname>message-properties</varname> struct, and |
| <varname>dp</varname> refers to an AMQP 0-10 |
| <varname>delivery-properties</varname> struct.</para> |
| |
| <table id="table-amqp0-10-message-properties" pgwide="1"> |
| <title>Mapping to AMQP 0-10 Message Properties</title> |
| <tgroup cols="3"> |
| <thead> |
| <colspec colnum="1" colname="Python API" colwidth="3*"/> |
| <colspec colnum="2" colname="C++ API" colwidth="3*"/> |
| <colspec colnum="3" colname="AMPQ 0-10 Property" colwidth="6*"/> |
| <row> |
| <entry>Python API</entry> |
| <entry>C++ API |
| <footnote> |
| <para> |
| The .NET Binding for C++ Messaging provides all the |
| message and delivery properties described in the C++ API. |
| See <xref linkend="table-Dotnet-Binding-Message" /> . |
| </para> |
| </footnote> |
| </entry> |
| <entry>AMQP 0-10 Property<footnote><para>In these entries, <literal>mp</literal> refers to an AMQP message property, and <literal>dp</literal> refers to an AMQP delivery property.</para></footnote></entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>msg.id</entry><entry>msg.{get,set}MessageId()</entry><entry>mp.message_id</entry> |
| </row> |
| <row> |
| <entry>msg.subject</entry><entry>msg.{get,set}Subject()</entry><entry>mp.application_headers["qpid.subject"]</entry> |
| </row> |
| <row> |
| <entry>msg.user_id</entry><entry>msg.{get,set}UserId()</entry><entry>mp.user_id</entry> |
| </row> |
| <row> |
| <entry>msg.reply_to</entry><entry>msg.{get,set}ReplyTo()</entry><entry>mp.reply_to<footnote><para>The reply_to is converted from the protocol representation into an address.</para></footnote></entry> |
| </row> |
| <row> |
| <entry>msg.correlation_id</entry><entry>msg.{get,set}CorrelationId()</entry><entry>mp.correlation_id</entry> |
| </row> |
| <row> |
| <entry>msg.durable</entry><entry>msg.{get,set}Durable()</entry><entry>dp.delivery_mode == delivery_mode.persistent<footnote><para>Note that msg.durable is a boolean, not an enum.</para></footnote></entry> |
| </row> |
| <row> |
| <entry>msg.priority</entry><entry>msg.{get,set}Priority()</entry><entry>dp.priority</entry> |
| </row> |
| <row> |
| <entry>msg.ttl</entry><entry>msg.{get,set}Ttl()</entry><entry>dp.ttl</entry> |
| </row> |
| <row> |
| <entry>msg.redelivered</entry><entry>msg.{get,set}Redelivered()</entry><entry>dp.redelivered</entry> |
| </row> |
| <row><entry>msg.properties</entry><entry>msg.getProperties()/msg.setProperty()</entry><entry>mp.application_headers</entry> |
| </row> |
| <row> |
| <entry>msg.content_type</entry><entry>msg.{get,set}ContentType()</entry><entry>mp.content_type</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| <section role="h3" id="section-amqp0-10-message-props"> |
| <title>0-10 Message Property Keys</title> |
| <para> |
| The QPID Messaging API also recognises special message property keys and |
| automatically provides a mapping to their corresponding AMQP 0-10 definitions. |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| When sending a message, if the properties contain an entry for |
| <literal>x-amqp-0-10.app-id</literal>, its value will be used to set the |
| <literal>message-properties.app-id</literal> property in the outgoing |
| message. Likewise, if an incoming message has |
| <literal>message-properties.app-id</literal> set, its value can be accessed |
| via the <literal>x-amqp-0-10.app-id</literal> message property key. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| When sending a message, if the properties contain an entry for |
| <literal>x-amqp-0-10.content-encoding</literal>, its value will be used to |
| set the <literal>message-properties.content-encoding</literal> property in |
| the outgoing message. Likewise, if an incoming message has |
| <literal>message-properties.content-encoding</literal> set, its value can be |
| accessed via the <literal>x-amqp-0-10.content-encoding</literal> message |
| property key. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The routing key (<literal>delivery-properties.routing-key</literal>) in an |
| incoming messages can be accessed via the |
| <literal>x-amqp-0-10.routing-key</literal> message property. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| If the timestamp delivery property is set in an incoming message |
| (<literal>delivery-properties.timestamp</literal>), the timestamp value will |
| be made available via the <literal>x-amqp-0-10.timestamp</literal> message |
| property. |
| <footnote> |
| <para> |
| This special property is currently not supported by the Qpid JMS client. |
| </para> |
| </footnote> |
| </para> |
| </listitem> |
| </itemizedlist> |
| <example> |
| <title>Accessing the AMQP 0-10 Message Timestamp in Python</title> |
| <para> |
| The following code fragment checks for and extracts the message timestamp from |
| a received message. |
| </para> |
| <programlisting lang="python"> |
| try: |
| msg = receiver.fetch(timeout=1) |
| if "x-amqp-0-10.timestamp" in msg.properties: |
| print("Timestamp=%s" % str(msg.properties["x-amqp-0-10.timestamp"])) |
| except Empty: |
| pass |
| </programlisting> |
| </example> |
| <example> |
| <title>Accessing the AMQP 0-10 Message Timestamp in C++</title> |
| <para> |
| The same example, except in C++. |
| </para> |
| <programlisting lang="c++"> |
| messaging::Message msg; |
| if (receiver.fetch(msg, messaging::Duration::SECOND*1)) { |
| if (msg.getProperties().find("x-amqp-0-10.timestamp") != msg.getProperties().end()) { |
| <![CDATA[std::cout << "Timestamp=" << msg.getProperties()["x-amqp-0-10.timestamp"].asString() << std::endl;]]> |
| } |
| } |
| </programlisting> |
| </example> |
| </section> |
| </section> |
| |
| <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Message-Groups-Guide.xml"/> |
| |
| </chapter> |
| |
| <chapter> |
| <title>The .NET Binding for the C++ Messaging Client</title> |
| <para> |
| The .NET Binding for the C++ Qpid Messaging Client is a library that gives |
| any .NET program access to Qpid C++ Messaging objects and methods. |
| </para> |
| <section> |
| <title>.NET Binding for the C++ Messaging Client Component Architecture</title> |
| |
| <programlisting><![CDATA[ |
| +----------------------------+ |
| | Dotnet examples | |
| | Managed C# | |
| +------+---------------+-----+ |
| | | |
| V | |
| +---------------------------+ | |
| | .NET Managed Callback | | |
| | org.apache.qpid.messaging.| | |
| | sessionreceiver.dll | | |
| +----------------------+----+ | |
| | | |
| managed V V |
| (.NET) +--------------------------------+ |
| :::::::::::::::::::::::| .NET Binding Library |:::::::::::: |
| unmanaged | org.apache.qpid.messaging.dll | |
| (Native Win32/64) +---------------+----------------+ |
| | |
| | |
| +----------------+ | |
| | Native examples| | |
| | Unmanaged C++ | | |
| +--------+-------+ | |
| | | |
| V V |
| +----------------------------------+ |
| | QPID Messaging C++ Libraries | |
| | qpid*.dll qmf*.dll | |
| +--------+--------------+----------+ |
| ]]></programlisting> |
| |
| |
| <para>This diagram illustrates the code and library components of the binding |
| and the hierarchical relationships between them.</para> |
| |
| <table id="table-Dotnet-Binding-Component-Architecture" > |
| <title>.NET Binding for the C++ Messaging Client Component Architecture</title> |
| <tgroup cols="2"> |
| <thead> |
| <row> |
| <entry>Component Name</entry> |
| <entry>Component Function</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>QPID Messaging C++ Libraries</entry> |
| <entry>The QPID Messaging C++ core run time system</entry> |
| </row> |
| <row> |
| <entry>Unmanaged C++ Example Source Programs</entry> |
| <entry>Ordinary C++ programs that illustrate using qpid/cpp Messaging directly |
| in a native Windows environment.</entry> |
| </row> |
| <row> |
| <entry>.NET Messaging Binding Library</entry> |
| <entry>The .NET Messaging Binding library provides interoprability between |
| managed .NET programs and the unmanaged, native Qpid Messaging C++ core |
| run time system. .NET programs create a Reference to this library thereby |
| exposing all of the native C++ Messaging functionality to programs |
| written in any .NET language.</entry> |
| </row> |
| <row> |
| <entry>.NET Messaging Managed Callback Library</entry> |
| <entry>An extension of the .NET Messaging Binding Library that provides message |
| callbacks in a managed .NET environment.</entry> |
| </row> |
| <row> |
| <entry>Managed C# .NET Example Source Programs</entry> |
| <entry>Various C# example programs that illustrate using .NET Binding for C++ Messaging in the .NET environment.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| |
| <section> |
| <title>.NET Binding for the C++ Messaging Client Examples</title> |
| |
| <para>This chapter describes the various sample programs that |
| are available to illustrate common Qpid Messaging usage.</para> |
| |
| <table id="table-Dotnet-Binding-Example-Client-Server"> |
| <title>Example : Client - Server</title> |
| <tgroup cols="2"> |
| <colspec colname="c1"/> |
| <colspec colname="c2"/> |
| <thead> |
| <row> |
| <entry>Example Name</entry> |
| <entry>Example Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>csharp.example.server</entry> |
| <entry>Creates a Receiver and listens for messages. |
| Upon message reception the message content is converted to upper case |
| and forwarded to the received message's ReplyTo address.</entry> |
| </row> |
| <row> |
| <entry>csharp.example.client</entry> |
| <entry>Sends a series of messages to the Server and prints the original message |
| content and the received message content.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| <table id="table-Dotnet-Binding-Example-MapSender-MapReceiver"> |
| <title>Example : Map Sender – Map Receiver</title> |
| <tgroup cols="2"> |
| <colspec colname="c1"/> |
| <colspec colname="c2"/> |
| <thead> |
| <row> |
| <entry>Example Name</entry> |
| <entry>Example Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>csharp.map.receiver</entry> |
| <entry>Creates a Receiver and listens for a map message. |
| Upon message reception the message is decoded and displayed on the console.</entry> |
| </row> |
| <row> |
| <entry>csharp.map.sender</entry> |
| <entry>Creates a map message and sends it to map.receiver. |
| The map message contains values for every supported .NET Messaging |
| Binding data type.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| <table id="table-Dotnet-Binding-Example-Spout-Drain"> |
| <title>Example : Spout - Drain</title> |
| <tgroup cols="2"> |
| <colspec colname="c1"/> |
| <colspec colname="c2"/> |
| <thead> |
| <row> |
| <entry>Example Name</entry> |
| <entry>Example Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>csharp.example.spout</entry> |
| <entry>Spout is a more complex example of code that generates a series of messages |
| and sends them to peer program Drain. Flexible command line arguments allow |
| the user to specify a variety of message and program options.</entry> |
| </row> |
| <row> |
| <entry>csharp.example.drain</entry> |
| <entry>Drain is a more complex example of code that receives a series of messages |
| and displays their contents on the console.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| <table id="table-Dotnet-Binding-Example-CallbackSender-CallbackReceiver"> |
| <title>Example : Map Callback Sender – Map Callback Receiver</title> |
| <tgroup cols="2"> |
| <colspec colname="c1"/> |
| <colspec colname="c2"/> |
| <thead> |
| <row> |
| <entry>Example Name</entry> |
| <entry>Example Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>csharp.map.callback.receiver</entry> |
| <entry>Creates a Receiver and listens for a map message. |
| Upon message reception the message is decoded and displayed on the console. |
| This example illustrates the use of the C# managed code callback mechanism |
| provided by .NET Messaging Binding Managed Callback Library.</entry> |
| </row> |
| <row> |
| <entry>csharp.map.callback.sender</entry> |
| <entry>Creates a map message and sends it to map_receiver. |
| The map message contains values for every supported .NET Messaging |
| Binding data type.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| <table id="table-Dotnet-Binding-Example-DeclareQueues"> |
| <title>Example - Declare Queues</title> |
| <tgroup cols="2"> |
| <colspec colname="c1"/> |
| <colspec colname="c2"/> |
| <thead> |
| <row> |
| <entry>Example Name</entry> |
| <entry>Example Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>csharp.example.declare_queues</entry> |
| <entry>A program to illustrate creating objects on a broker. |
| This program creates a queue used by spout and drain.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| <table id="table-Dotnet-Binding-Example-DirectSender-DirectReceiver"> |
| <title>Example: Direct Sender - Direct Receiver</title> |
| <tgroup cols="2"> |
| <colspec colname="c1"/> |
| <colspec colname="c2"/> |
| <thead> |
| <row> |
| <entry>Example Name</entry> |
| <entry>Example Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>csharp.direct.receiver</entry> |
| <entry>Creates a Receiver and listens for a messages. |
| Upon message reception the message is decoded and displayed on the console.</entry> |
| </row> |
| <row> |
| <entry>csharp.direct.sender</entry> |
| <entry> Creates a series of messages and sends them to csharp.direct.receiver.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| <table id="table-Dotnet-Binding-Example-Helloworld"> |
| <title>Example: Hello World</title> |
| <tgroup cols="2"> |
| <colspec colname="c1"/> |
| <colspec colname="c2"/> |
| <thead> |
| <row> |
| <entry>Example Name</entry> |
| <entry>Example Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>csharp.example.helloworld</entry> |
| <entry>A program to send a message and to receive the same message.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| </section> |
| |
| <section> |
| <title>.NET Binding Class Mapping to Underlying C++ Messaging API</title> |
| |
| <para>This chapter describes the specific mappings between |
| classes in the .NET Binding and the underlying C++ Messaging |
| API.</para> |
| |
| <section> |
| <title>.NET Binding for the C++ Messaging API Class: Address</title> |
| <table id="table-Dotnet-Binding-Address"> |
| <title>.NET Binding for the C++ Messaging API Class: Address</title> |
| <tgroup cols="2"> |
| <colspec colname="c1" colwidth="1*"/> |
| <colspec colname="c2" colwidth="7*"/> |
| <thead> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">.NET Binding Class: Address</entry> |
| </row> |
| <row> |
| <entry>Language</entry> |
| <entry>Syntax</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>C++</entry> |
| <entry>class Address</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ref class Address</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Address();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Address();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Address(const std::string& address);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Address(string address);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Address(const std::string& name, const std::string& subject, const qpid::types::Variant::Map& options, const std::string& type = "");</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Address(string name, string subject, Dictionary<string, object> options);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Address(string name, string subject, Dictionary<string, object> options, string type);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Address(const Address& address);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Address(Address address);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Destructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>~Address();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>~Address();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Finalizer</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>!Address();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy assignment operator</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Address& operator=(const Address&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Address op_Assign(Address rhs);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Name</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const std::string& getName() const;</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setName(const std::string&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string Name { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Subject</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const std::string& getSubject() const;</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setSubject(const std::string&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string Subject { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Options</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const qpid::types::Variant::Map& getOptions() const;</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>qpid::types::Variant::Map& getOptions();</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setOptions(const qpid::types::Variant::Map&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Dictionary<string, object> Options { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Type</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>std::string getType() const;</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setType(const std::string&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string Type { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Miscellaneous</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>std::string str() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string ToStr();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Miscellaneous</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>operator bool() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Miscellaneous</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>bool operator !() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>n/a</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| <section> |
| <title>.NET Binding for the C++ Messaging API Class: Connection</title> |
| <table id="table-Dotnet-Binding-Connection"> |
| <title>.NET Binding for the C++ Messaging API Class: Connection</title> |
| <tgroup cols="2"> |
| <colspec colname="c1" colwidth="1*"/> |
| <colspec colname="c2" colwidth="7*"/> |
| <thead> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">.NET Binding Class: Connection</entry> |
| </row> |
| <row> |
| <entry>Language</entry> |
| <entry>Syntax</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>C++</entry> |
| <entry>class Connection : public qpid::messaging::Handle<ConnectionImpl></entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ref class Connection</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Connection(ConnectionImpl* impl);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Connection();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Connection(const std::string& url, const qpid::types::Variant::Map& options = qpid::types::Variant::Map());</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Connection(string url);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Connection(string url, Dictionary<string, object> options);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Connection(const std::string& url, const std::string& options);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Connection(string url, string options); </entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Connection(const Connection&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Connection(Connection connection);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Destructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>~Connection();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>~Connection();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Finalizer</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>!Connection();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy assignment operator</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Connection& operator=(const Connection&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Connection op_Assign(Connection rhs);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: SetOption</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setOption(const std::string& name, const qpid::types::Variant& value);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void SetOption(string name, object value);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: open</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void open();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Open();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: isOpen</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>bool isOpen();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool IsOpen { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: close</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void close();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Close();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: createTransactionalSession</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Session createTransactionalSession(const std::string& name = std::string());</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Session CreateTransactionalSession();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Session CreateTransactionalSession(string name);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: createSession</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Session createSession(const std::string& name = std::string());</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Session CreateSession();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Session CreateSession(string name);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: getSession</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Session getSession(const std::string& name) const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Session GetSession(string name);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: AuthenticatedUsername</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>std::string getAuthenticatedUsername();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string GetAuthenticatedUsername();</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| <section> |
| <title>.NET Binding for the C++ Messaging API Class: Duration</title> |
| <table id="table-Dotnet-Binding-Duration"> |
| <title>.NET Binding for the C++ Messaging API Class: Duration</title> |
| <tgroup cols="2"> |
| <colspec colname="c1" colwidth="1*"/> |
| <colspec colname="c2" colwidth="7*"/> |
| <thead> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">.NET Binding Class: Duration</entry> |
| </row> |
| <row> |
| <entry>Language</entry> |
| <entry>Syntax</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>C++</entry> |
| <entry>class Duration</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ref class Duration</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>explicit Duration(uint64_t milliseconds);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Duration(ulong mS);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Duration(Duration rhs);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Destructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>default</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>default</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Finalizer</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>default</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Milliseconds</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint64_t getMilliseconds() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ulong Milliseconds { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Operator: *</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Duration operator*(const Duration& duration, uint64_t multiplier);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public static Duration operator *(Duration dur, ulong multiplier);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public static Duration Multiply(Duration dur, ulong multiplier);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Duration operator*(uint64_t multiplier, const Duration& duration);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public static Duration operator *(ulong multiplier, Duration dur);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public static Duration Multiply(ulong multiplier, Duration dur);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constants</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>static const Duration FOREVER;</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>static const Duration IMMEDIATE;</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>static const Duration SECOND;</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>static const Duration MINUTE;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public sealed class DurationConstants</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public static Duration FORVER;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public static Duration IMMEDIATE;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public static Duration MINUTE;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public static Duration SECOND;</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| <section> |
| <title>.NET Binding for the C++ Messaging API Class: FailoverUpdates</title> |
| <table id="table-Dotnet-Binding-FailoverUpdates"> |
| <title>.NET Binding for the C++ Messaging API Class: FailoverUpdates</title> |
| <tgroup cols="2"> |
| <colspec colname="c1" colwidth="1*"/> |
| <colspec colname="c2" colwidth="7*"/> |
| <thead> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">.NET Binding Class: FailoverUpdates</entry> |
| </row> |
| <row> |
| <entry>Language</entry> |
| <entry>Syntax</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>C++</entry> |
| <entry>class FailoverUpdates</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ref class FailoverUpdates</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>FailoverUpdates(Connection& connection);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public FailoverUpdates(Connection connection);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Destructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>~FailoverUpdates();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>~FailoverUpdates();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Finalizer</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>!FailoverUpdates();</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| <section> |
| <title>.NET Binding for the C++ Messaging API Class: Message</title> |
| <table id="table-Dotnet-Binding-Message"> |
| <title>.NET Binding for the C++ Messaging API Class: Message</title> |
| <tgroup cols="2"> |
| <colspec colname="c1" colwidth="1*"/> |
| <colspec colname="c2" colwidth="7*"/> |
| <thead> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">.NET Binding Class: Message</entry> |
| </row> |
| <row> |
| <entry>Language</entry> |
| <entry>Syntax</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>C++</entry> |
| <entry>class Message</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ref class Message</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Message(const std::string& bytes = std::string());</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>Message();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>Message(System::String ^ theStr);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>Message(System::Object ^ theValue);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>Message(array<System::Byte> ^ bytes);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Message(const char*, size_t);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Message(byte[] bytes, int offset, int size);</entry> |
| </row> |
| <row> |
| <entry> </entry> |
| <entry>Copy constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Message(const Message&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Message(Message message);</entry> |
| </row> |
| <row> |
| <entry> </entry> |
| <entry>Copy assignment operator</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Message& operator=(const Message&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Message op_Assign(Message rhs);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Destructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>~Message();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>~Message();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Finalizer</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>!Message()</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: ReplyTo</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setReplyTo(const Address&);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const Address& getReplyTo() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Address ReplyTo { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Subject</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setSubject(const std::string&);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const std::string& getSubject() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string Subject { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: ContentType</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setContentType(const std::string&);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const std::string& getContentType() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string ContentType { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: MessageId</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setMessageId(const std::string&);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const std::string& getMessageId() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string MessageId { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: UserId</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setUserId(const std::string&);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const std::string& getUserId() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string UserId { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: CorrelationId</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setCorrelationId(const std::string&);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const std::string& getCorrelationId() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string CorrelationId { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Priority</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setPriority(uint8_t);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint8_t getPriority() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public byte Priority { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Ttl</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setTtl(Duration ttl);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Duration getTtl() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Duration Ttl { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Durable</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setDurable(bool durable);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>bool getDurable() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool Durable { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Redelivered</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>bool getRedelivered() const;</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setRedelivered(bool);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool Redelivered { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: SetProperty</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setProperty(const std::string&, const qpid::types::Variant&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void SetProperty(string name, object value);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Properties</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const qpid::types::Variant::Map& getProperties() const;</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>qpid::types::Variant::Map& getProperties();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Dictionary<string, object> Properties { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: SetContent</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setContent(const std::string&);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setContent(const char* chars, size_t count);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void SetContent(byte[] bytes);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void SetContent(string content);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void SetContent(byte[] bytes, int offset, int size);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: GetContent</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>std::string getContent() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string GetContent();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void GetContent(byte[] arr);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void GetContent(Collection<object> __p1);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void GetContent(Dictionary<string, object> dict);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: GetContentPtr</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const char* getContentPtr() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: ContentSize</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>size_t getContentSize() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ulong ContentSize { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Struct: EncodingException</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>struct EncodingException : qpid::types::Exception</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: decode</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void decode(const Message& message, qpid::types::Variant::Map& map, const std::string& encoding = std::string());</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void decode(const Message& message, qpid::types::Variant::List& list, const std::string& encoding = std::string());</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: encode</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void encode(const qpid::types::Variant::Map& map, Message& message, const std::string& encoding = std::string());</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void encode(const qpid::types::Variant::List& list, Message& message, const std::string& encoding = std::string());</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: AsString</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string AsString(object obj);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string ListAsString(Collection<object> list);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string MapAsString(Dictionary<string, object> dict);</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| <section> |
| <title>.NET Binding for the C++ Messaging API Class: Receiver</title> |
| <table id="table-Dotnet-Binding-Receiver"> |
| <title>.NET Binding for the C++ Messaging API Class: Receiver</title> |
| <tgroup cols="2"> |
| <colspec colname="c1" colwidth="1*"/> |
| <colspec colname="c2" colwidth="7*"/> |
| <thead> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">.NET Binding Class: Receiver</entry> |
| </row> |
| <row> |
| <entry>Language</entry> |
| <entry>Syntax</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>C++</entry> |
| <entry>class Receiver</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ref class Receiver</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>Constructed object is returned by Session.CreateReceiver</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Receiver(const Receiver&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Receiver(Receiver receiver);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Destructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>~Receiver();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>~Receiver();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Finalizer</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>!Receiver()</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy assignment operator</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Receiver& operator=(const Receiver&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Receiver op_Assign(Receiver rhs);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Get</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>bool get(Message& message, Duration timeout=Duration::FOREVER);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool Get(Message mmsgp);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool Get(Message mmsgp, Duration durationp);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Get</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Message get(Duration timeout=Duration::FOREVER);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Message Get();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Message Get(Duration durationp);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Fetch</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>bool fetch(Message& message, Duration timeout=Duration::FOREVER);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool Fetch(Message mmsgp);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool Fetch(Message mmsgp, Duration duration);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Fetch</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Message fetch(Duration timeout=Duration::FOREVER);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Message Fetch();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Message Fetch(Duration durationp);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Capacity</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setCapacity(uint32_t);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint32_t getCapacity();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public uint Capacity { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Available</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint32_t getAvailable();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public uint Available { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Unsettled</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint32_t getUnsettled();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public uint Unsettled { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Close</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void close();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Close();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: IsClosed</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>bool isClosed() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool IsClosed { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Name</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const std::string& getName() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string Name { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Session</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Session getSession() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Session Session { get; }</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| <section> |
| <title>.NET Binding for the C++ Messaging API Class: Sender</title> |
| <table id="table-Dotnet-Binding-Sender"> |
| <title>.NET Binding for the C++ Messaging API Class: Sender</title> |
| <tgroup cols="2"> |
| <colspec colname="c1" colwidth="1*"/> |
| <colspec colname="c2" colwidth="7*"/> |
| <thead> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">.NET Binding Class: Sender</entry> |
| </row> |
| <row> |
| <entry>Language</entry> |
| <entry>Syntax</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>C++</entry> |
| <entry>class Sender</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ref class Sender</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>Constructed object is returned by Session.CreateSender</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Sender(const Sender&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Sender(Sender sender);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Destructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>~Sender();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>~Sender();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Finalizer</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>!Sender()</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy assignment operator</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Sender& operator=(const Sender&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Sender op_Assign(Sender rhs);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Send</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void send(const Message& message, bool sync=false);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Send(Message mmsgp);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Send(Message mmsgp, bool sync);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Close</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void close();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Close();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Capacity</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void setCapacity(uint32_t);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint32_t getCapacity();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public uint Capacity { get; set; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Available</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint32_t getAvailable();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public uint Available { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Unsettled</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint32_t getUnsettled();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public uint Unsettled { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Name</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>const std::string& getName() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public string Name { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Session</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Session getSession() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Session Session { get; }</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| <section> |
| <title>.NET Binding for the C++ Messaging API Class: Session</title> |
| <table id="table-Dotnet-Binding-Session"> |
| <title>.NET Binding for the C++ Messaging API Class: Session</title> |
| <tgroup cols="2"> |
| <colspec colname="c1" colwidth="1*"/> |
| <colspec colname="c2" colwidth="7*"/> |
| <thead> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">.NET Binding Class: Session</entry> |
| </row> |
| <row> |
| <entry>Language</entry> |
| <entry>Syntax</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>C++</entry> |
| <entry>class Session</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public ref class Session</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Constructor</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>Constructed object is returned by Connection.CreateSession</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy constructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Session(const Session&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Session(Session session);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Destructor</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>~Session();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>~Session();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Finalizer</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>n/a</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>!Session()</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Copy assignment operator</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Session& operator=(const Session&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Session op_Assign(Session rhs);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Close</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void close();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Close();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Commit</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void commit();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Commit();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Rollback</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void rollback();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Rollback();</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Acknowledge</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void acknowledge(bool sync=false);</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void acknowledge(Message&, bool sync=false);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Acknowledge();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Acknowledge(bool sync);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Acknowledge(Message __p1);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Acknowledge(Message __p1, bool __p2);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Reject</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void reject(Message&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Reject(Message __p1);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Release</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void release(Message&);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Release(Message __p1);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: Sync</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void sync(bool block=true);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Sync();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void Sync(bool block);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Receivable</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint32_t getReceivable();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public uint Receivable { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: UnsettledAcks</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>uint32_t getUnsettledAcks();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public uint UnsetledAcks { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: NextReceiver</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>bool nextReceiver(Receiver&, Duration timeout=Duration::FOREVER);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool NextReceiver(Receiver rcvr);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool NextReceiver(Receiver rcvr, Duration timeout);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: NextReceiver</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Receiver nextReceiver(Duration timeout=Duration::FOREVER);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Receiver NextReceiver();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Receiver NextReceiver(Duration timeout);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: CreateSender</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Sender createSender(const Address& address);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Sender CreateSender(Address address);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: CreateSender</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Sender createSender(const std::string& address);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Sender CreateSender(string address);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: CreateReceiver</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Receiver createReceiver(const Address& address);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Receiver CreateReceiver(Address address);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: CreateReceiver</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Receiver createReceiver(const std::string& address);</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Receiver CreateReceiver(string address);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: GetSender</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Sender getSender(const std::string& name) const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Sender GetSender(string name);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: GetReceiver</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Receiver getReceiver(const std::string& name) const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Receiver GetReceiver(string name);</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: Connection</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>Connection getConnection() const;</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public Connection Connection { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Property: HasError</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>bool hasError();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public bool HasError { get; }</entry> |
| </row> |
| <row> |
| <entry namest="c1" nameend="c2" align="center">Method: CheckError</entry> |
| </row> |
| <row> |
| <entry>C++</entry> |
| <entry>void checkError();</entry> |
| </row> |
| <row> |
| <entry>.NET</entry> |
| <entry>public void CheckError();</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| <section> |
| <title>.NET Binding Class: SessionReceiver</title> |
| <para> |
| The SessionReceiver class provides a convenient callback |
| mechanism for Messages received by all Receivers on a given |
| Session. |
| </para> |
| <para> |
| <programlisting><![CDATA[ |
| using Org.Apache.Qpid.Messaging; |
| using System; |
| |
| namespace Org.Apache.Qpid.Messaging.SessionReceiver |
| { |
| public interface ISessionReceiver |
| { |
| void SessionReceiver(Receiver receiver, Message message); |
| } |
| |
| public class CallbackServer |
| { |
| public CallbackServer(Session session, ISessionReceiver callback); |
| |
| public void Close(); |
| } |
| } |
| ]]> |
| </programlisting> |
| </para> |
| <para> |
| To use this class a client program includes references to both |
| Org.Apache.Qpid.Messaging and Org.Apache.Qpid.Messaging.SessionReceiver. |
| The calling program creates a function that implements the |
| ISessionReceiver interface. This function will be called whenever |
| message is received by the session. The callback process is started |
| by creating a CallbackServer and will continue to run until the |
| client program calls the CallbackServer.Close function. |
| </para> |
| <para> |
| A complete operating example of using the SessionReceiver callback |
| is contained in cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver. |
| </para> |
| </section> |
| </section> |
| </chapter> |
| </book> |
| |
| <!-- |
| - client code remains exactly the same, but routing behavior |
| changes |
| - exchanges drop messages if nobody is listening, so we need to |
| start drain first |
| - drain will exit immediately if the source is empty (note that |
| this is actually a semantic guarantee provided by the API, we |
| know for a fact that the source is empty when drain/fetch |
| reports it, no fudge factor timeout is required [this assumes |
| nobody is concurrently publishing of course]) |
| - drain -f invokes blocking fetch (you could use a timeout here also) |
| --> |