Modified: qpid/java/trunk/doc/jms-client-0-10/src/docbkx/JMS-Client-0-10-Book.xml URL: http://svn.apache.org/viewvc/qpid/java/trunk/doc/jms-client-0-10/src/docbkx/JMS-Client-0-10-Book.xml?rev=1743761&r1=1743760&r2=1743761&view=diff ============================================================================== --- qpid/java/trunk/doc/jms-client-0-10/src/docbkx/JMS-Client-0-10-Book.xml (original) +++ qpid/java/trunk/doc/jms-client-0-10/src/docbkx/JMS-Client-0-10-Book.xml Fri May 13 21:45:57 2016 @@ -20,347 +20,11 @@ --> -<book xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="client-api-tutorial"> - <title>Programming in Apache Qpid</title> - <subtitle>Cross-Platform AMQP Messaging in Java JMS, .NET, C++, and Python</subtitle> +<book xmlns="http://docbook.org/ns/docbook" version="5.0"> + <title>Qpid AMQP 0-10 JMS Client</title> <chapter> - <title>Introduction</title> - - <para>Apache Qpid is a reliable, asynchronous messaging system that - supports the AMQP messaging protocol in several common programming - languages. Qpid is supported on most common platforms. - </para> - - <itemizedlist> - <listitem> - <para> - On the Java platform, Qpid uses the - established <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://java.sun.com/products/jms/">Java JMS - API</link>. - </para> - </listitem> - <listitem> - <para> - For Python, C++, and .NET, Qpid defines its own messaging API, the - <firstterm>Qpid Messaging API</firstterm>, which is - conceptually similar in each. - </para> - <para> - On the .NET platform, Qpid also provides a WCF binding. - </para> - </listitem> - <listitem> - <para> - Ruby will also use the Qpid Messaging API, which will soon - be implemented. (Ruby currently uses an API that is closely - tied to the AMQP version). - </para> - </listitem> - </itemizedlist> - - </chapter> - - <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 xml:lang="c++"> - #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 xml:id="hello-cpp-open" linkends="callout-cpp-open"/> - Session session = connection.createSession(); <co xml:id="hello-cpp-session" linkends="callout-cpp-session"/> - - Receiver receiver = session.createReceiver(address); <co xml:id="hello-cpp-receiver" linkends="callout-cpp-receiver"/> - Sender sender = session.createSender(address); <co xml:id="hello-cpp-sender" linkends="callout-cpp-sender"/> - - sender.send(Message("Hello world!")); - - Message message = receiver.fetch(Duration::SECOND * 1); <co xml:id="hello-cpp-fetch" linkends="callout-cpp-fetch"/> - std::cout << message.getContent() << std::endl; - session.acknowledge(); <co xml:id="hello-cpp-acknowledge" linkends="callout-cpp-acknowledge"/> - - connection.close(); <co xml:id="hello-cpp-close" linkends="callout-cpp-close"/> - return 0; - } catch(const std::exception& error) { - std::cerr << error.what() << std::endl; - connection.close(); - return 1; - } - }</programlisting> - - <calloutlist> - <callout xml:id="callout-cpp-open" arearefs="hello-cpp-open"> - <para>Establishes the connection with the messaging broker.</para> - </callout> - <callout xml:id="callout-cpp-session" arearefs="hello-cpp-session"> - <para>Creates a session object on which messages will be sent and received.</para> - </callout> - <callout xml:id="callout-cpp-receiver" arearefs="hello-cpp-receiver"> - <para>Creates a receiver that receives messages from the given address.</para> - </callout> - <callout xml:id="callout-cpp-sender" arearefs="hello-cpp-sender"> - <para>Creates a sender that sends to the given address.</para> - </callout> - <callout xml: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 xml: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 xml: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 xml:lang="python"> - 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 xml:id="hello-python-open" linkends="callout-python-open"/> - session = connection.session() <co xml:id="hello-python-session" linkends="callout-python-session"/> - - sender = session.sender(address) <co xml:id="hello-python-sender" linkends="callout-python-sender"/> - receiver = session.receiver(address) <co xml:id="hello-python-receiver" linkends="callout-python-receiver"/> - - sender.send(Message("Hello world!")); - - message = receiver.fetch(timeout=1) <co xml:id="hello-python-fetch" linkends="callout-python-fetch"/> - print message.content - session.acknowledge() <co xml:id="hello-python-acknowledge" linkends="callout-python-acknowledge"/> - - except MessagingError,m: - print m - finally: - connection.close() <co xml:id="hello-python-close" linkends="callout-python-close"/> - </programlisting> - - <calloutlist> - <callout xml:id="callout-python-open" arearefs="hello-python-open"> - <para>Establishes the connection with the messaging broker.</para> - </callout> - <callout xml:id="callout-python-session" arearefs="hello-python-session"> - <para>Creates a session object on which messages will be sent and received.</para> - </callout> - <callout xml:id="callout-python-receiver" arearefs="hello-python-receiver"> - <para>Creates a receiver that receives messages from the given address.</para> - </callout> - <callout xml:id="callout-python-sender" arearefs="hello-python-sender"> - <para>Creates a sender that sends to the given address.</para> - </callout> - <callout xml: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 xml: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 xml: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 xml:lang="c++"> - using System; - using Org.Apache.Qpid.Messaging; <co xml: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 xml:id="hello-csharp-open" linkends="callout-csharp-open"/> - Session session = connection.CreateSession(); <co xml:id="hello-csharp-session" linkends="callout-csharp-session"/> - - Receiver receiver = session.CreateReceiver(address); <co xml:id="hello-csharp-receiver" linkends="callout-csharp-receiver"/> - Sender sender = session.CreateSender(address); <co xml: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 xml:id="hello-csharp-fetch" linkends="callout-csharp-fetch"/> - Console.WriteLine("{0}", message.GetContent()); - session.Acknowledge(); <co xml:id="hello-csharp-acknowledge" linkends="callout-csharp-acknowledge"/> - - connection.Close(); <co xml:id="hello-csharp-close" linkends="callout-csharp-close"/> - } catch (Exception e) { - Console.WriteLine("Exception {0}.", e); - if (null != connection) - connection.Close(); - } - } - } - } - - </programlisting> - - <calloutlist> - <callout xml: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 xml:id="callout-csharp-open" arearefs="hello-csharp-open"> - <para>Establishes the connection with the messaging broker.</para> - </callout> - <callout xml:id="callout-csharp-session" arearefs="hello-csharp-session"> - <para>Creates a session object on which messages will be sent and received.</para> - </callout> - <callout xml:id="callout-csharp-receiver" arearefs="hello-csharp-receiver"> - <para>Creates a receiver that receives messages from the given address.</para> - </callout> - <callout xml:id="callout-csharp-sender" arearefs="hello-csharp-sender"> - <para>Creates a sender that sends to the given address.</para> - </callout> - <callout xml: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 xml: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 xml: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> - - - - - + <title>Addresses</title> <section xml:id="section-addresses"> <title>Addresses</title> @@ -1429,1207 +1093,661 @@ spout - -content "$(cat rdu.xml | sed -e </section> - <section xml:id="replay"> - <title>Sender Capacity and Replay</title> + </chapter> - <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> + <!-- TODO: move above somewhere else --> - <section xml: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> + <chapter xml:id="QpidJMS"> + <title>Using the Qpid JMS client</title> + <section> + <title>A Simple Messaging Program in Java JMS</title> - <section xml:id="acknowledgements"> - <title>Acknowledging Received Messages</title> + <para>The following program shows how to send and receive a + message using the Qpid JMS client. JMS programs typically use + JNDI to obtain connection factory and destination objects which + the application needs. In this way the configuration is kept + separate from the application code itself.</para> - <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> + <para>In this example, we create a JNDI context using a + properties file, use the context to lookup a connection factory, + create and start a connection, create a session, and lookup a + destination from the JNDI context. Then we create a producer and + a consumer, send a message with the producer and receive it with + the consumer. This code should be straightforward for anyone + familiar with Java JMS.</para> - </section> + <example> + <title>"Hello world!" in Java</title> + <programlisting xml:lang="java"> + package org.apache.qpid.example.jmsexample.hello; + import javax.jms.*; + import javax.naming.Context; + import javax.naming.InitialContext; + import java.util.Properties; - <section> - <title>Receiving Messages from Multiple Sources</title> + public class Hello { - <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> + public Hello() { + } + + public static void main(String[] args) { + Hello producer = new Hello(); + producer.runTest(); + } - <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> + private void runTest() { + try { + Properties properties = new Properties(); + properties.load(this.getClass().getResourceAsStream("hello.properties")); <co xml:id="hello-java-properties" linkends="callout-java-properties"/> + Context context = new InitialContext(properties); <co xml:id="hello-java-context" linkends="callout-java-context"/> - <example> - <title>Receiving Messages from Multiple Sources</title> + ConnectionFactory connectionFactory + = (ConnectionFactory) context.lookup("qpidConnectionfactory"); <co xml:id="hello-java-connection-factory" linkends="callout-java-connection-factory"/> + Connection connection = connectionFactory.createConnection(); <co xml:id="hello-java-connection" linkends="callout-java-connection"/> + connection.start(); <co xml:id="hello-java-start" linkends="callout-java-start"/> - <para>C++:</para> + Session session=connection.createSession(false,Session.AUTO_ACKNOWLEDGE);<co xml:id="hello-java-session" linkends="callout-java-session"/> + Destination destination = (Destination) context.lookup("topicExchange"); <co xml:id="hello-java-destination" linkends="callout-java-destination"/> - <programlisting> - 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> + MessageProducer messageProducer = session.createProducer(destination); <co xml:id="hello-java-producer" linkends="callout-java-producer"/> + MessageConsumer messageConsumer = session.createConsumer(destination); <co xml:id="hello-java-consumer" linkends="callout-java-consumer"/> - <para>Python:</para> - <programlisting> - 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> + TextMessage message = session.createTextMessage("Hello world!"); + messageProducer.send(message); - <para>.NET C#:</para> - <programlisting> - 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> + message = (TextMessage)messageConsumer.receive(); <co xml:id="hello-java-receive" linkends="callout-java-receive"/> + System.out.println(message.getText()); + connection.close(); <co xml:id="hello-java-close" linkends="callout-java-close"/> + context.close(); <co xml:id="hello-java-jndi-close" linkends="callout-java-jndi-close"/> + } + catch (Exception exp) { + exp.printStackTrace(); + } + } + } + </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> + <calloutlist> + <callout xml:id="callout-java-properties" arearefs="hello-java-properties"> + <para>Loads the JNDI properties file, which specifies connection properties, queues, topics, and addressing options. See <xref linkend="QpidJNDI"/> for details.</para> + </callout> + <callout xml:id="callout-java-context" arearefs="hello-java-context"> + <para>Creates the JNDI initial context.</para> + </callout> + <callout xml:id="callout-java-connection-factory" arearefs="hello-java-connection-factory"> + <para>Creates a JMS connection factory for Qpid.</para> + </callout> + <callout xml:id="callout-java-connection" arearefs="hello-java-connection"> + <para>Creates a JMS connection.</para> + </callout> + <callout xml:id="callout-java-start" arearefs="hello-java-start"> + <para>Activates the connection.</para> + </callout> + <callout xml:id="callout-java-session" arearefs="hello-java-session"> + <para>Creates a session. This session is not transactional (transactions='false'), and messages are automatically acknowledged.</para> + </callout> + <callout xml:id="callout-java-destination" arearefs="hello-java-destination"> + <para>Creates a destination for the topic exchange, so senders and receivers can use it.</para> + </callout> + <callout xml:id="callout-java-producer" arearefs="hello-java-producer"> + <para>Creates a producer that sends messages to the topic exchange.</para> + </callout> + <callout xml:id="callout-java-consumer" arearefs="hello-java-consumer"> + <para>Creates a consumer that reads messages from the topic exchange.</para> + </callout> + <callout xml:id="callout-java-receive" arearefs="hello-java-receive"> + <para>Reads the next available message.</para> + </callout> + <callout xml:id="callout-java-close" arearefs="hello-java-close"> + <para>Closes the connection, all sessions managed by the connection, and all senders and receivers managed by each session.</para> + </callout> + <callout xml:id="callout-java-jndi-close" arearefs="hello-java-jndi-close"> + <para>Closes the JNDI context.</para> + </callout> + </calloutlist> - .</para> + <para>The contents of the hello.properties file are shown below.</para> <example> - <title>Transactions</title> - <para>C++:</para> + <title>JNDI Properties File for "Hello world!" example</title> <programlisting> - Connection connection(broker); - Session session = connection.createTransactionalSession(); - ... - if (smellsOk()) - session.commit(); - else - session.rollback(); - </programlisting> - <para> - .NET C#: - </para> + java.naming.factory.initial + = org.apache.qpid.jndi.PropertiesFileInitialContextFactory - <programlisting> - Connection connection = new Connection(broker); - Session session = connection.CreateTransactionalSession(); - ... - if (smellsOk()) - session.Commit(); - else - session.Rollback(); + # connectionfactory.[jndiname] = [ConnectionURL] + connectionfactory.qpidConnectionfactory + = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672' <co xml:id="hello-properties-connectionfactory" linkends="callout-hello-properties-connectionfactory"/> + # destination.[jndiname] = [address_string] + destination.topicExchange = amq.topic <co xml:id="hello-properties-destination" linkends="callout-hello-properties-destination"/> </programlisting> - <!-- - <para>Python</para> - <programlisting><![CDATA[ - ### TODO - ]]></programlisting> - --> </example> + <calloutlist> + <callout xml:id="callout-hello-properties-connectionfactory" arearefs="hello-properties-connectionfactory"> + <para>Defines a connection factory from which connections + can be created. The syntax of a ConnectionURL is given in + <xref linkend="QpidJNDI"/>.</para> + </callout> + <callout xml:id="callout-hello-properties-destination" arearefs="hello-properties-destination"> + <para>Defines a destination for which MessageProducers + and/or MessageConsumers can be created to send and receive + messages. The value for the destination in the properties + file is an address string as described in + <xref linkend="section-addresses"/>. In the JMS + implementation MessageProducers are analogous to senders in + the Qpid Message API, and MessageConsumers are analogous to + receivers.</para> + </callout> + </calloutlist> + </section> - <section xml: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> + <section xml:id="QpidJNDI"> + <title>Apache Qpid JNDI Properties for AMQP Messaging</title> - <programlisting> - 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. + Apache Qpid defines JNDI properties that can be used to specify JMS Connections and Destinations. Here is a typical JNDI properties file: </para> - <section xml: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> - + <example> + <title>JNDI Properties File</title> <programlisting> - 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> + java.naming.factory.initial + = org.apache.qpid.jndi.PropertiesFileInitialContextFactory - <programlisting> - localhost - localhost:5672 - localhost:9999 - 192.168.1.2:5672 - mybroker.example.com:5672 - amqp:tcp:localhost:5672 - tcp:locahost:5672,localhost:5800 + # connectionfactory.[jndiname] = [ConnectionURL] + connectionfactory.qpidConnectionfactory + = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672' + # destination.[jndiname] = [address_string] + destination.topicExchange = amq.topic </programlisting> + </example> - </section> + <para>The following sections describe the JNDI properties that Qpid uses.</para> - <section xml: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> - 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> - connection = Connection("localhost:5672", reconnect=True) - try: - connection.open() - !!! SNIP !!! - </programlisting> - - <para>or</para> - - <programlisting> - 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"> + + <section> + <title>JNDI Properties for Apache Qpid</title> + <para> + Apache Qpid supports the properties shown in the following table: + </para> + <table> + <title>JNDI Properties supported by Apache Qpid</title> + <tgroup cols="2"> <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> + <entry> + Property + </entry> + <entry> + Purpose + </entry> </row> </thead> <tbody> - <row> - <entry> - <literal>username</literal> - </entry> - <entry> - string - </entry> - <entry> - The username to use when authenticating to the broker. - </entry> + <entry> + connectionfactory.<jndiname> + </entry> + <entry> + <para> + The Connection URL that the connection factory uses to perform connections. + </para> + </entry> </row> <row> - <entry> - <literal>password</literal> - </entry> - <entry> - string - </entry> - <entry> - The password to use when authenticating to the broker. - </entry> + <entry> + queue.<jndiname> + </entry> + <entry> + <para> + A JMS queue, which is implemented as an amq.direct exchange in Apache Qpid. + </para> + </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> + <entry> + topic.<jndiname> + </entry> + <entry> + <para> + A JMS topic, which is implemented as an amq.topic exchange in Apache Qpid. + </para> + </entry> </row> - - <row> - <entry> - <literal>reconnect</literal> - </entry> - <entry> - boolean - </entry> - <entry> - Transparently reconnect if the connection is lost. - </entry> + <entry> + destination.<jndiname> + </entry> + <entry> + <para> + Can be used for defining all amq destinations, + queues, topics and header matching, using an + address string. + + <footnote><para>Binding URLs, which were used in + earlier versions of the Qpid Java JMS client, can + still be used instead of address + strings.</para></footnote> + </para> + </entry> + </row> + </tbody> + </tgroup> + </table> + </section> + + <section xml:id="section-jms-connection-url"> + <title>Connection URLs</title> + <para> + In JNDI properties, a Connection URL specifies properties for a connection. The format for a Connection URL is: + </para> + + <programlisting>amqp://[<user>:<pass>@][<clientid>]<virtualhost>[?<option>='<value>'[&<option>='<value>']] + </programlisting> + <para> + For instance, the following Connection URL specifies a user name, a password, a client ID, a virtual host ("test"), a broker list with a single broker, and a TCP host with the host name <quote>localhost</quote> using port 5672: + </para> + + <programlisting>amqp://username:password@clientid/test?brokerlist='tcp://localhost:5672' + </programlisting> + <para> + Apache Qpid supports the following properties in Connection URLs: + </para> + <table pgwide="1"> + <title>Connection URL Properties</title> + <tgroup cols="3"> + <thead> + <row> + <entry> + Option + </entry> + <entry> + Type + </entry> + <entry> + Description + </entry> </row> + </thead> + <tbody> <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> + <entry> + brokerlist + </entry> + <entry> + see below + </entry> + <entry> + List of one or more broker addresses. + </entry> </row> <row> - <entry> - <literal>reconnect_limit</literal> - </entry> - <entry> + <entry> + maxprefetch + </entry> + <entry> integer - </entry> - <entry> - Maximum number of reconnection attempts before giving up and raising an exception. - </entry> + </entry> + <entry> + <para> + The maximum number of pre-fetched messages per consumer. If not specified, default value of 500 is used. + </para> + <para> + Note: You can also set the default per-consumer prefetch value on a client-wide basis by configuring the client using <link linkend="client-jvm-properties">Java system properties.</link> + </para> + </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> + <entry> + sync_publish + </entry> + <entry> + {'persistent' | 'all'} + </entry> + <entry> + A sync command is sent after every persistent message to guarantee that it has been received; if the value is 'persistent', this is done only for persistent messages. + </entry> </row> <row> - <entry> - <literal>reconnect_interval_max</literal> - </entry> - <entry> - integer representing time in seconds - </entry> - <entry> - Maximum reconnect interval. - </entry> + <entry> + sync_ack + </entry> + <entry> + Boolean + </entry> + <entry> + A sync command is sent after every acknowledgement to guarantee that it has been received. + </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> + <entry> + use_legacy_map_msg_format + </entry> + <entry> + Boolean + </entry> + <entry> + If you are using JMS Map messages and deploying a new client with any JMS client older than 0.8 release, you must set this to true to ensure the older clients can understand the map message encoding. + </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> + <entry> + failover + </entry> + <entry> + {'singlebroker' | 'roundrobin' | 'failover_exchange' | 'nofailover' | '<class>'} + </entry> + <entry> + <para> + This option controls failover behaviour. The method <literal>singlebroker</literal> uses only the first broker in the list, + <literal>roundrobin</literal> will try each broker given in the broker list until a connection is established, + <literal>failover_exchange</literal> connects to the initial broker given in the broker URL and will receive membership updates + via the failover exchange. <literal>nofailover</literal> disables all retry and failover logic. Any other value is interpreted as a + classname which must implement the <literal>org.apache.qpid.jms.failover.FailoverMethod</literal> interface. + </para> + <para> + The broker list options <literal>retries</literal> and <literal>connectdelay</literal> (described below) determine the number of times a + connection to a broker will be retried and the the length of time to wait between successive connection attempts before moving on to + the next broker in the list. The failover option <literal>cyclecount</literal> controls the number of times to loop through the list of + available brokers before finally giving up. + </para> + <para> + Defaults to <literal>roundrobin</literal> if the brokerlist contains multiple brokers, or <literal>singlebroker</literal> otherwise. + </para> + </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> + <entry> + ssl + </entry> + <entry> + boolean + </entry> + <entry> + <para> + If <literal>ssl='true'</literal>, use SSL for all broker connections. Overrides any per-broker settings in the brokerlist (see below) entries. If not specified, the brokerlist entry for each given broker is used to determine whether SSL is used. + </para> + <para> + Introduced in version 0.22. + </para> + </entry> </row> </tbody> </tgroup> - </table> - - </section> - </section> - - <section xml: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> + </table> + <para> + Broker lists are specified using a URL in this format: + </para> - <para>The Qpid Messaging API supports <classname>map</classname> and <classname>list</classname> in message content. + <programlisting>brokerlist=<transport>://<host>[:<port>](?<param>='<value>')(&<param>='<value>')*</programlisting> + <para> + For instance, this is a typical broker list: + </para> - <footnote><para>Unlike JMS, there is not a specific message type for - map messages.</para></footnote> + <programlisting>brokerlist='tcp://localhost:5672' + </programlisting> - <footnote> <para> - Note that the Qpid JMS client supports MapMessages whose values can be nested maps or lists. This is not standard JMS behaviour. + A broker list can contain more than one broker address; if so, the connection is made to the first broker in the list that is available. In general, it is better to use the failover exchange when using multiple brokers, since it allows applications to fail over if a broker goes down. </para> - </footnote> - Specific language support for <classname>map</classname> and <classname>list</classname> objects are shown in the following table. - </para> - <table xml: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 xml: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> + <title>Broker Lists</title> + <para>A broker list can specify properties to be used when connecting to the broker, such as security options. This broker list specifies options for a Kerberos connection using GSSAPI:</para> <programlisting> - 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 xml: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> - - - + amqp://guest:guest@test/test?sync_ack='true' + &brokerlist='tcp://ip1:5672?sasl_mechs='GSSAPI'' + </programlisting> - <section xml:id="section-cpp-Maps"> - <title>Qpid Maps and Lists in C++</title> + <para>This broker list specifies SSL options:</para> + <programlisting> + amqp://guest:guest@test/test?sync_ack='true' + &brokerlist='tcp://ip1:5672?ssl='true'&ssl_cert_alias='cert1'' + </programlisting> - <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> + <para> + This broker list specifies two brokers using the connectdelay and retries broker options. It also illustrates the failover connection URL + property. + </para> - <example> - <title>Sending Qpid Maps and Lists in C++</title> <programlisting> - 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> + amqp://guest:guest@/test?failover='roundrobin?cyclecount='2'' + &brokerlist='tcp://ip1:5672?retries='5'&connectdelay='2000';tcp://ip2:5672?retries='5'&connectdelay='2000'' + </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> + <para>The following broker list options are supported.</para> - <table xml:id="table-cpp-Maps"> - <title>C++ Datatypes in Maps</title> + <table pgwide="1"> + <title>Broker List Options</title> <tgroup cols="3"> <thead> <row> - <entry>C++ Datatype</entry> - <entry> Python</entry> - <entry>Java</entry> + <entry> + Option + </entry> + <entry> + Type + </entry> + <entry> + Description + </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 xml: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> - 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 xml: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> + <entry> + heartbeat + </entry> + <entry> + integer + </entry> + <entry> + Frequency of heartbeat messages (in seconds). A value of 0 disables heartbeating. <para>For compatibility + with old client configuration, option <varname>idle_timeout</varname> (in milliseconds) is also supported.</para> + </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 xml: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>Dictionary<string, object> - <footnoteref linkend="callout-dotnet-string"/></entry></row> - <row><entry>Variant::List</entry><entry>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>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> - 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> - #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> - 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> + <row> + <entry> + sasl_mechs + </entry> + <entry> + -- + </entry> + <entry> + For secure applications, we suggest CRAM-MD5, + DIGEST-MD5, or GSSAPI. The ANONYMOUS method is not + secure. The PLAIN method is secure only when used + together with SSL. For Kerberos, sasl_mechs must be + set to GSSAPI, sasl_protocol must be set to the + principal for the qpidd broker, e.g. qpidd/, and + sasl_server must be set to the host for the SASL + server, e.g. sasl.com. SASL External is supported + using SSL certification, e.g. + <literal>ssl='true'&sasl_mechs='EXTERNAL'</literal> + </entry> + </row> + <row> + <entry> + sasl_encryption + </entry> + <entry> + Boolean + </entry> + <entry> + If <literal>sasl_encryption='true'</literal>, the JMS client attempts to negotiate a security layer with the broker using GSSAPI to encrypt the connection. Note that for this to happen, GSSAPI must be selected as the sasl_mech. + </entry> + </row> + <row> + <entry> + sasl_protocol + </entry> + <entry> + -- + </entry> + <entry> + Used only for + Kerberos. <literal>sasl_protocol</literal> must be + set to the principal for the qpidd broker, + e.g. <literal>qpidd/</literal> + </entry> + </row> + <row> + <entry> + sasl_server + </entry> + <entry> + -- + </entry> + <entry> + For Kerberos, sasl_mechs must be set to GSSAPI, + sasl_server must be set to the host for the SASL + server, e.g. <literal>sasl.com</literal>. + </entry> + </row> + <row> + <entry> + trust_store + </entry> + <entry> + -- + </entry> + <entry> + path to trust store + </entry> + </row> + <row> + <entry> + trust_store_password + </entry> + <entry> + -- + </entry> + <entry> + Trust store password + </entry> + </row> + <row> + <entry> + key_store + </entry> + <entry> + -- + </entry> + <entry> + path to key store + </entry> + </row> + <row> + <entry> + key_store_password + </entry> + <entry> + -- + </entry> + <entry> + key store password + </entry> + </row> + <row> + <entry> + ssl + </entry> + <entry> + Boolean + </entry> + <entry> + <para>If <literal>ssl='true'</literal>, the JMS client will encrypt the connection to this broker using SSL.</para> - <programlisting>from qpid.log import enable, DEBUG - enable("qpid.messaging.io", DEBUG) - </programlisting> - <para> - For more information on Python logging, see <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://docs.python.org/lib/node425.html">http://docs.python.org/lib/node425.html</link>. For more information on Qpid logging, use <command>$ pydoc qpid.log</command>. - </para> + <para>This can also be set/overridden for all brokers using the <link linkend="section-jms-connection-url">Connection URL</link> options.</para> + </entry> + </row> + <row> + <entry> + ssl_verify_hostname + </entry> + <entry> + Boolean + </entry> + <entry> + When using SSL you can enable hostname verification + by using <literal>ssl_verify_hostname='true'</literal> in the broker + URL. + </entry> + </row> + <row> + <entry> + ssl_cert_alias + </entry> + <entry> + -- + </entry> + <entry> + If multiple certificates are present in the keystore, the alias will be used to extract the correct certificate. + </entry> + </row> + <row> + <entry> + retries + </entry> + <entry> + integer + </entry> + <entry> + The number of times to retry connection to each broker in the broker list. Defaults to 1. + </entry> + </row> + <row> + <entry> + connectdelay + </entry> + <entry> + integer + </entry> + <entry> + Length of time (in milliseconds) to wait before attempting to reconnect. Defaults to 0. + </entry> + </row> + <row> + <entry> + connecttimeout + </entry> + <entry> + integer + </entry> + <entry> + Length of time (in milliseconds) to wait for the socket connection to succeed. A value of 0 represents an infinite timeout, i.e. the connection attempt will block until established or an error occurs. Defaults to 30000. + </entry> + </row> + <row> + <entry> + tcp_nodelay + </entry> + <entry> + Boolean + </entry> + <entry> + If <literal>tcp_nodelay='true'</literal>, TCP packet + batching is disabled. Defaults to true since Qpid 0.14. + </entry> + </row> + </tbody> + </tgroup> + </table> </section> </section> - - - <section xml: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> + <section> + <title>Java JMS Message Properties</title> <para>The following table shows how Qpid Messaging API message properties are mapped to AMQP 0-10 message properties and @@ -2640,3939 +1758,600 @@ spout - -content "$(cat rdu.xml | sed -e <varname>dp</varname> refers to an AMQP 0-10 <varname>delivery-properties</varname> struct.</para> - <table xml:id="table-amqp0-10-message-properties" pgwide="1"> - <title>Mapping to AMQP 0-10 Message Properties</title> - <tgroup cols="3"> + <table> + <title>Java JMS Mapping to AMQP 0-10 Message Properties</title> + <tgroup cols="2"> <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>Java JMS Message Property</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> + <entry>JMSMessageID</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> + <entry>qpid.subject<footnote><para>This is a custom JMS property, set automatically by the Java JMS client implementation.</para></footnote></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> + <entry>JMSXUserID</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> + <entry>JMSReplyTo</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> + <entry>JMSCorrelationID</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> + <entry>JMSDeliveryMode</entry><entry>dp.delivery_mode</entry> </row> <row> - <entry>msg.priority</entry><entry>msg.{get,set}Priority()</entry><entry>dp.priority</entry> + <entry>JMSPriority</entry><entry>dp.priority</entry> </row> <row> - <entry>msg.ttl</entry><entry>msg.{get,set}Ttl()</entry><entry>dp.ttl</entry> + <entry>JMSExpiration</entry><entry>dp.ttl<footnote><para>JMSExpiration = dp.ttl + currentTime</para></footnote></entry> </row> <row> - <entry>msg.redelivered</entry><entry>msg.{get,set}Redelivered()</entry><entry>dp.redelivered</entry> + <entry>JMSRedelivered</entry><entry>dp.redelivered</entry> </row> - <row><entry>msg.properties</entry><entry>msg.getProperties()/msg.setProperty()</entry><entry>mp.application_headers</entry> + <row> + <entry>JMS Properties</entry><entry>mp.application_headers</entry> </row> <row> - <entry>msg.content_type</entry><entry>msg.{get,set}ContentType()</entry><entry>mp.content_type</entry> + <entry>JMSType</entry><entry>mp.content_type</entry> </row> </tbody> </tgroup> </table> - <section role="h3" xml: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 xml: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 xml: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()) { - 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> + <section xml:id="section-JMS-MapMessage"> + <title>JMS MapMessage Types</title> + <para>Qpid supports the Java JMS <classname>MapMessage</classname> interface, which provides support for maps in messages. The following code shows how to send a <classname>MapMessage</classname> in Java JMS.</para> - <chapter xml:id="QpidJMS"> - <title>Using the Qpid JMS client</title> - <section> - <title>A Simple Messaging Program in Java JMS</title> + <example> + <title>Sending a Java JMS MapMessage</title> + <programlisting> + import java.util.ArrayList; + import java.util.HashMap; + import java.util.List; + import java.util.Map; - <para>The following program shows how to send and receive a - message using the Qpid JMS client. JMS programs typically use - JNDI to obtain connection factory and destination objects which - the application needs. In this way the configuration is kept - separate from the application code itself.</para> + import javax.jms.Connection; + import javax.jms.Destination; + import javax.jms.MapMessage; + import javax.jms.MessageProducer; + import javax.jms.Session; - <para>In this example, we create a JNDI context using a - properties file, use the context to lookup a connection factory, - create and start a connection, create a session, and lookup a - destination from the JNDI context. Then we create a producer and - a consumer, send a message with the producer and receive it with - the consumer. This code should be straightforward for anyone - familiar with Java JMS.</para> + import java.util.Arrays; - <example> - <title>"Hello world!" in Java</title> - <programlisting xml:lang="java"> - package org.apache.qpid.example.jmsexample.hello; + // !!! SNIP !!! - import javax.jms.*; - import javax.naming.Context; - import javax.naming.InitialContext; - import java.util.Properties; + MessageProducer producer = session.createProducer(queue); - public class Hello { + MapMessage m = session.createMapMessage(); + m.setIntProperty("Id", 987654321); + m.setStringProperty("name", "Widget"); + m.setDoubleProperty("price", 0.99); - public Hello() { - } + List<String> colors = new ArrayList<String>(); + colors.add("red"); + colors.add("green"); + colors.add("white"); + m.setObject("colours", colors); - public static void main(String[] args) { - Hello producer = new Hello(); - producer.runTest(); - } + Map<String,Double> dimensions = new HashMap<String,Double>(); + dimensions.put("length",10.2); + dimensions.put("width",5.1); + dimensions.put("depth",2.0); + m.setObject("dimensions",dimensions); - private void runTest() { - try { - Properties properties = new Properties(); - properties.load(this.getClass().getResourceAsStream("hello.properties")); <co xml:id="hello-java-properties" linkends="callout-java-properties"/> - Context context = new InitialContext(properties); <co xml:id="hello-java-context" linkends="callout-java-context"/> + List<List<Integer>> parts = new ArrayList<List<Integer>>(); + parts.add(Arrays.asList(new Integer[] {1,2,5})); + parts.add(Arrays.asList(new Integer[] {8,2,5})); + m.setObject("parts", parts); - ConnectionFactory connectionFactory - = (ConnectionFactory) context.lookup("qpidConnectionfactory"); <co xml:id="hello-java-connection-factory" linkends="callout-java-connection-factory"/> - Connection connection = connectionFactory.createConnection(); <co xml:id="hello-java-connection" linkends="callout-java-connection"/> - connection.start(); <co xml:id="hello-java-start" linkends="callout-java-start"/>
[... 4130 lines stripped ...] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
