1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
|
<?xml version="1.0"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
[
<!ENTITY % entities SYSTEM "commonEntities.xml">
%entities;
]>
<!--
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.
-->
<chapter id="JMS-Client-0-8-Client-Understanding">
<title>Understanding the Qpid JMS client</title>
<section id="JMS-Client-0-8-Client-Understanding-Overview">
<title>Overview</title>
<para>The Qpid JMS client provides a JMS 1.1 compliant implementation. As such, the primary
source of documentation is the <ulink url="&oracleJmsSpec;">JMS specification</ulink> and the
<ulink url="&oracleJeeDocUrl;/javax/jms/package-summary.html">JMS javadocs</ulink>. This
documentation assumes the reader has familiarity with these resources.</para>
<para>The remainder of this section describes how the Qpid JMS client behaves and the effect(s)
making JMS method calls will have on the Broker. </para>
<para>There areas where the Qpid JMS client provides features beyond those required for JMS
compliance. These are described in the sections that follow.</para>
<para>These sections are also used to bring out differences that may surprise those moving from
JMS implementations provided by other vendors.</para>
<figure>
<title>Architecture of a typical JMS application</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/QpidJmsOverview.png" format="PNG" scalefit="1"/>
</imageobject>
</mediaobject>
</figure>
</section>
<section id="JMS-Client-0-8-Client-Understanding-ConnectionFactory">
<title>ConnectionFactory</title>
<para>A <ulink url="&oracleJeeDocUrl;javax/jms/ConnectionFactory.html">ConnectionFactory</ulink>
allows an application to create a <ulink url="&oracleJeeDocUrl;javax/jms/Connection.html"
>Connection</ulink>.</para>
<para>The application obtains the ConnectionFactory from an <ulink
url="&oracleJdkDocUrl;javax/naming/InitialContext.html">InitialContext</ulink>. The
InitialContext is itself obtained from an InitialContextFactory. </para>
<para>The Qpid JMS client provides a single implementation of the InitialContextFactory in class
<literal>org.apache.qpid.jndi.PropertiesFileInitialContextFactory</literal>. This
implementation is backed by a <ulink url="&oracleJdkDocUrl;java/util/Properties.html"
>Properties</ulink> object which can of course be loaded from an external properties file,
or created programatically.</para>
<para>The examples in the previous chapter illustrated the Java code required to <link
linkend="JMS-Client-0-8-Examples-PTP">create the InitialContext</link> and an <link
linkend="JMS-Client-0-8-Examples-PTP-PropertiesFile">example properties file</link>.</para>
<para>Note that the Qpid Broker does not present a JNDI interface to the application.</para>
<figure>
<title>JNDI overview</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/JndiOverview.png" format="PNG" scalefit="1"/>
</imageobject>
</mediaobject>
</figure>
</section>
<section id="JMS-Client-0-8-Client-Understanding-Connection">
<title>Connection</title>
<para>A Connection represents an open communication channel between application and
Broker.</para>
<para>Connections are created from the ConnectionFactory <footnote>
<para>Constructors of the AMQConnection class must not be used.</para>
</footnote>.</para>
<para>Each connection utilises a single TCP/IP connection between the process of the application
and the process of the Broker. The act of establishing a connection is therefore a relatively
expensive operation. It is recommended that the same connection is used for a series of
message interactions. Patterns utilising a connection per message should not be used. </para>
<para>The underlying TCP/IP connection remains open for the lifetime of the JMS connection. It
is closed when the application calls <ulink
url="&oracleJeeDocUrl;javax/jms/Connection.html#close()">Connection#close()</ulink>, but it
can also be closed if the connection is closed from the Broker side (via a Management
operation or broker shutdown or running into coditions which AMQP specifications treats as errors and mandates closing the connection).
The JMS connection will also be closed if the underlying TCP/IP connection is broken.</para>
<para>Qpid connections have failover and heartbeating capabilities. They support SSL and
client-auth. These are described in the sub-sections that follow.</para>
<section id="JMS-Client-0-8-Client-Understanding-Connection-Failover">
<title>Failover</title>
<para>Qpid connections support a failover feature. This is the ability to automatically
re-establish a failed connection, either to the same Broker, or the next Broker in the
broker list.</para>
<para>This failover process is done in a manner that is mostly transparent to the application.
After a successful failover, any existing Connection, Session, MessageConsumer and
MessageProducer objects held by the application remain valid.</para>
<para>If a failover occurs during the scope of a JMS Transaction, any work performed by that
transaction is lost. The application is made aware of this loss by way of the <ulink
url="&oracleJeeDocUrl;javax/jms/TransactionRolledBackException.html"
>TransactionRolledBackException</ulink> from the <ulink
url="&oracleJeeDocUrl;javax/jms/Session.html#commit">Session#commit()</ulink> call.
Applications utilising failover must be prepared to catch this exception and respond by
either repeating the work of the transaction, or by propagating a rollback to the
originating system.</para>
<para>If, after all retries are exhausted, failover has failed to reconnect the application,
the Connection's <ulink url="&oracleJeeDocUrl;javax/jms/ExceptionListener.html"
>ExceptionListener</ulink> will receive a JMSException with a linked exception of <ulink
url="JMS-Client-0-8-Appendix-Exceptions-AMQDisconnectedException"
>AMQDisconnectedException</ulink>. Any further use of the JMS objects (Connection, Session
etc), will results in a <ulink url="&oracleJeeDocUrl;javax/jms/IllegalStateException.html"
>IllegalStateException</ulink>.</para>
<para>Configure failover using the Connection URL. Here's an example Connection URL utilising
failover between two brokers. Note the use of the broker options <link
linkend="JMS-Client-0-8-Connection-URL-BrokerOptions-Retries"
><literal>retries</literal></link> and <link
linkend="JMS-Client-0-8-Connection-URL-BrokerOptions-ConnectDelay"
><literal>connectdelay</literal></link> to control the number of connection attempts to
each individual broker, and the delay between each connection attempt. Also note the use of
the <emphasis>failover option</emphasis>
<literal>cyclecount</literal> to control the number of times the failover mechanism will
traverse the brokerlist.</para>
<example>
<title>Connection URL configured for failover</title>
<screen><![CDATA[
amqp://username:password@clientid/test
?brokerlist='tcp://localhost:15672?retries='10'&connectdelay='1000';tcp://localhost:25672?retries='10'&connectdelay='1000''
&failover='roundrobin?cyclecount='20'']]>
</screen>
</example>
<para>For full details see <xref linkend="JMS-Client-0-8-Connection-URL"/></para>
<note><para>Note, that a single broker failover is enabled by default. If the failover behaviour is not desired it can be switched off
by setting a failover option to <emphasis>nofailover</emphasis> as in the example below
<example>
<title>Connection URL configured with nofailover</title>
<screen><![CDATA[
amqp://username:password@clientid/test
?brokerlist='tcp://localhost:15672?failover='nofailover']]>
</screen>
</example>
</para></note>
<!-- TODO perhaps mention ConnectionListener?-->
</section>
<section id="JMS-Client-0-8-Client-Understanding-Connection-Heartbeating">
<title>Heartbeating</title>
<para>Qpid connections support heartbeating. When enabled, the Qpid JMS client and Broker
exchange a heartbeat during periods of inactivity. This allows both peers to discover if the
TCP/IP connection becomes inoperable in a timely manner.</para>
<para>This feature is sometimes useful in applications that must traverse firewalls as the
heartbeat prevents connections from being closed during periods when there is no application
traffic.</para>
<para>It is also allows the both the JMS client and the Broker to confirm that the other is
<emphasis>minimally</emphasis> responsive. (It does nothing however to determine the
health of the higher level tiers of application, for this reason, applications may implement
an application level heartbeat either in addition to, or instead of the heartbeat.</para>
<para>If the client ever fails to receive two consecutive heartbeats, the Connection will be
automatically closed and the Connection's <ulink
url="&oracleJeeDocUrl;javax/jms/ExceptionListener.html">ExceptionListener</ulink> will
receive a JMSException with a linked exception of AMQDisconnectedException. Any further use
of the JMS objects (Connection, Session etc), will results in a <ulink
url="&oracleJeeDocUrl;javax/jms/IllegalStateException.html"
>IllegalStateException</ulink>.</para>
<para>To enable heartbeating either use a Connection URL including the broker option <link
linkend="JMS-Client-0-8-Connection-URL-BrokerOptions-Heartbeat"
><literal>heartbeat</literal></link>, or use the system property <link
linkend="JMS-Client-0-8-System-Properties-Heartbeat"
><literal>qpid.heartbeat</literal></link>. </para>
<example>
<title>Connection URL configured for heartbeating</title>
<screen><![CDATA[
amqp://guest:guest@clientid/?brokerlist='localhost:5672?heartbeat='5'']]>
</screen>
</example>
</section>
<section id="JMS-Client-0-8-Client-Understanding-Connection-SSL">
<title>SSL</title>
<para>The Qpid JMS client supports connections encrypted using Secure Socket Layer (SSL) and
SSL-Client Authentication. SSL is configured using Connection URL. To use SSL, SSL must be
be configured on the Broker.</para>
<para>Some example Connection URLs using SSL follow:</para>
<itemizedlist>
<listitem>
<para>Simple SSL when the Broker is secured by a certificate that is signed by a CA which
is trusted by the JVM.</para>
<example>
<title>Connection URL configured for SSL - CA trusted by JVM</title>
<screen><![CDATA[
amqp://guest:guest@clientid/?brokerlist='localhost:5671'&ssl='true']]>
</screen>
</example>
</listitem>
<listitem>
<para>SSL when the Broker is secured by a certificate that is signed by a CA which is NOT
trusted by the JVM (such as when a organisation is using a private CA, or self-signed
certificates are in use). For this case, we use <link
linkend="JMS-Client-0-8-Connection-URL-BrokerOptions-TrustStore"
><literal>trust_store</literal></link> and <link
linkend="JMS-Client-0-8-Connection-URL-BrokerOptions-TrustStorePassword"
><literal>trust_store_password</literal></link> to specify a path a truststore file
(containing the certificate of the private-CA) and the truststore password.</para>
<example>
<title>Connection URL configured for SSL - CA not trusted by JVM</title>
<screen><![CDATA[
amqp://guest:guest@clientid/?brokerlist='localhost:5671?trust_store='/path/to/acme_org_ca.ts'&trust_store_password='secret''&ssl='true']]>
</screen>
</example>
</listitem>
<listitem>
<para>SSL with SSL client-auth. For this case, we use <link
linkend="JMS-Client-0-8-Connection-URL-BrokerOptions-KeyStore"
><literal>key_store</literal></link> and <link
linkend="JMS-Client-0-8-Connection-URL-BrokerOptions-KeyStorePassword"
><literal>key_store_password</literal></link> to specify a path a keystore file
(containing the certificate of the client) and the keystore password.</para>
<example>
<title>Connection URL configured for SSL - SSL client-auth</title>
<screen><![CDATA[
amqp://guest:guest@clientid/?brokerlist='localhost:5671?key_store='/path/to/app1_client_cert.ks'&key_store_password='secret''&ssl='true']]>
</screen>
</example>
</listitem>
</itemizedlist>
</section>
</section>
<section id="JMS-Client-0-8-Client-Understanding-Session">
<title>Session</title>
<para>A Session object is a single-threaded context for producing and consuming messages.</para>
<para>Session objects are created from the Connection. Whilst Session objects are relatively
lightweight, patterns utilising a single Session per message are not recommended.</para>
<para>The number of sessions open per connection at any one time is limited. This value is
negotiated when the connection is made. It defaults to 256.</para>
<para>Qpid JMS Sessions have the ability to prefetch messages to improve consumer performance.
This feature is described next.</para>
<section id="JMS-Client-0-8-Client-Understanding-Session-Prefecth">
<title>Prefetch</title>
<para>Prefetch specifies how many messages the client will optimistically cache for delivery
to a consumer. This is a useful parameter to tune that can improve the throughput of an
application. The prefetch buffer is scoped per <emphasis>Session</emphasis>.</para>
<para>The size of the prefetch buffer can be tuned per Connection using the connection url
option <link linkend="JMS-Client-0-8-Connection-URL-ConnectionOptions-Maxprefetch"
><literal>maxprefetch</literal></link> (or JVM wide using the system property <link
linkend="JMS-Client-0-8-System-Properties-Maxprefetch"
><literal>max_prefetch</literal></link>). By default, prefetch defaults to 500.</para>
<para>There are situations when you may wish to consider reducing the size of prefetch:</para>
<para>
<orderedlist>
<listitem>
<para>When using a <ulink url="http://www.eaipatterns.com/CompetingConsumers.html"
>Competing Consumers</ulink> pattern, prefetch can give the appearance of unequal
division of work. This will be apparent on startup when the queue has messages. The
first consumer started will cache prefetch size number of messages, possibly leaving
the other consumers with no initial work.</para>
</listitem>
<listitem>
<para>When using special queue types (such as LVQs, Sorted Queue and Priority Queues).
For these queue types the special delivery rules apply whilst the message resides on
the Broker. As soon as the message is sent to the client it delivery order is then
fixed. For example, if using a priority queue, and a prefetch of 100, and 100 messages
arrive with priority 2, the broker will send these to the client. If then a new
message arrives with priority 1, the broker cannot leap frog messages of the lower
priority. The priority 1 message will be delivered at the front of the next
batch.</para>
</listitem>
<listitem>
<para>When message size is large and you do not wish the memory footprint of the
application to grow (or suffer an OutOfMemoryError).</para>
</listitem>
</orderedlist>
</para>
<para>Finally, if using multiple MessageConsumers on a single Session, keep in mind that
unless you keep polling <emphasis>all</emphasis> consumers, it is possible for some traffic
patterns to result in consumer starvation and an application level deadlock. For example, if
prefetch is 100, and 100 hundred messages arrive suitable for consumer A, those messages
will be prefetched by the session, entirely filling the prefetch buffer. Now if the
application performs a blocking <ulink
url="&oracleJeeDocUrl;javax/jms/MessageConsumer.html#receive()"
>MessageConsumer#receive()</ulink> for Consumer B on the same Session, the application
will hang indefinitely as even if messages suitable for B arrive at the Broker. Those
messages can never be sent to the Session as no space is available in prefetch. </para>
<note><para>Please note, when the acknowlegement mode <emphasis>Session#SESSION_TRANSACTED</emphasis>
or <emphasis>Session#CLIENT_ACKNOWLEDGE</emphasis> is set on a consuming session,
the prefetched messages are released from the prefetch buffer on transaction commit/rollback
(in case of acknowledgement mode <emphasis>Session#SESSION_TRANSACTED</emphasis> )
or acknowledgement of the messages receipt (in case of acknowledgement mode
<emphasis>Session#CLIENT_ACKNOWLEDGE</emphasis> ). If the consuming application does not commit/rollback
the receiving transaction (for example, due to mistakes in application exception handling logic),
the prefetched messages continue to remain in the prefetch buffer preventing the delivery of the following messages.
As result, the application might stop the receiving of the messages
until the transaction is committed/rolled back (for <emphasis>Session#SESSION_TRANSACTED</emphasis> )
or received messages are acknowledged (for <emphasis>Session#CLIENT_ACKNOWLEDGE</emphasis>).</para></note>
</section>
<section id="JMS-Client-0-8-Client-Understanding-Session-TemporaryQueues">
<title>TemporaryQueues</title>
<para>Qpid implements JMS temporary queues as AMQP auto-delete queues. The life cycle of these
queues deviates from the JMS specification.</para>
<para>AMQP auto-delete queues are deleted either when the <emphasis>last</emphasis> Consumer
closes, or the Connection is closed. If no Consumer is ever attached to the queue, the queue
will remain until the Connection is closed.</para>
<para>This deviation has no practical impact on the implementation of the <ulink
url="http://www.eaipatterns.com/RequestReply.html">request/reply messaging pattern</ulink>
utilising a per-request temporary reply queue. The reply to queue is deleted as the
application closes the Consumer awaiting the response. </para>
<para>Temporary queues are exposed to Management in the same way as normal queues. Temporary
queue names take the form string <literal>TempQueue</literal> followed by a random
UUID.</para>
<para>Note that <ulink url="&oracleJeeDocUrl;javax/jms/TemporaryQueue.html#delete()"
>TemporaryQueue#delete()</ulink> merely marks the queue as deleted on within the JMS
client (and prevents further use of the queue from the application), however, the Queue will
remain on the Broker until the Consumer (or Connection) is closed.</para>
</section>
<section id="JMS-Client-0-8-Client-Understanding-Session-CreateQueue">
<title>CreateQueue</title>
<para>In the Qpid JMS client, <ulink
url="&oracleJeeDocUrl;javax/jms/Session.html#createQueue(java.lang.String)"
>Session#createQueue()</ulink> accepts either a queue name, or a Binding URL. If only name
is specified the destination will be resolved into binding URL:
direct://amq.direct//<queue name>?routingkey=’<queue name>’&durable=’true’. </para>
<para>Calling Session#createQueue() has no effect on the Broker.</para>
<para>Reiterating the advice from the JMS javadoc, it is suggested that this method is not
generally used. Instead, application should lookup Destinations declared within JNDI.</para>
</section>
<section id="JMS-Client-0-8-Client-Understanding-Session-CreateTopic">
<title>CreateTopic</title>
<para>In the Qpid JMS client, <ulink
url="&oracleJeeDocUrl;javax/jms/Session.html#createTopic(java.lang.String)"
>Session#createTopic()</ulink> accepts either a topic name, or a Binding URL. If only name
is specified the destination will be resolved into binding URL: topic://amq.topic//<topic
name>?routingkey=’<topic name>’.</para>
<para>Calling Session#createTopic() has no effect on the Broker.</para>
<para>Reiterating the advice from the JMS javadoc, it is suggested that this method is not
generally used. Instead, application should lookup Destinations declared within JNDI.</para>
</section>
</section>
<section id="JMS-Client-0-8-Client-Understanding-MessageProducer">
<title>MessageProducer</title>
<para>A MessageProducer sends a message an <emphasis>Exchange</emphasis>. It is the Exchange
(within the Broker) that routes the message to zero or more queue(s). Routing is performed
according to rules expressed as <emphasis>bindings</emphasis> between the exchange and queues
and a <emphasis>routing key</emphasis> included with each message.</para>
<para>To understand how this mechanism is used to deliver messages to queues and topics, see
<ulink url="&qpidJavaBrokerBook;Java-Broker-Concepts-Exchanges.html">Exchanges</ulink>
within the Java Broker book.</para>
<para>It is important to understand that when not used on a transactional session, <ulink
url="&oracleJeeDocUrl;javax/jms/MessageProducer.html#send(javax.jms.Message)"
>MessageProducer#send()</ulink> is <emphasis>asynchronous</emphasis> in nature. When #send()
returns to the application, the application cannot be certain if the Broker has received the
message. The Qpid JMS client may not have yet started to send the message, the message could
residing in a TCP/IP buffer, or the messages could be in some intermediate buffer within the
Broker. If the application requires certainty the message has been received by the Broker, a
<ulink url="&oracleJeeDocUrl;javax/jms/Session.html#SESSION_TRANSACTED">transactional
session</ulink>
<emphasis>must</emphasis> be used.</para>
<para>Qpid JMS MessageProducers have a number of features above that required by JMS. These are
described in the sub-sections that follow.</para>
<section id="JMS-Client-0-8-Client-Understanding-MessageProducer-MandatoryMessage">
<title>Mandatory Messages</title>
<para>With this feature, publishing a message with a routing key for which no binding exists
on the exchange will result in the message being returned to the publisher's
connection.</para>
<para>The Message is returned to the application in an asynchronous fashion via the
Connection's <ulink url="&oracleJeeDocUrl;javax/jms/ExceptionListener.html"
>ExceptionListener</ulink>. When a message is returned, it will be invoked with a
JMSException whose linked exception is an <ulink
url="JMS-Client-0-8-Appendix-Exceptions-AMQNoRouteException">AMQNoRouteException</ulink>.
The returned message is available to the application by calling
AMQNoRouteException#getUndeliveredMessage(). The ExceptionListener will be invoked exactly
once for each returned message.</para>
<para>The mandatory message feature is turned <emphasis>on</emphasis> by default for Queue
destinations and <emphasis>off</emphasis> for Topic destinations. This can be overridden
using system properties <link linkend="JMS-Client-0-8-System-Properties-DefaultMandatory"
><literal>qpid.default_mandatory</literal></link> and <link
linkend="JMS-Client-0-8-System-Properties-DefaultMandatoryTopic"
><literal>qpid.default_mandatory_topic</literal></link> for Queues and Topics
respectively.</para>
<note><para>Please note, according to AMQP specifications the mandatory flag on a message tells the server
how to react if the message cannot be routed to a queue. If this flag is set, the server will return an unroutable message with a
Return method. If this flag is zero, the server silently drops the message. Please, refer <ulink url="&amqpSrc;">AMQP specifications</ulink>
for more details.</para></note>
</section>
<section id="JMS-Client-0-8-Client-Understanding-MessageProducer-CloseWhenNoRoute">
<title>Close When No Route</title>
<para>With this feature, if a mandatory message is published with a routing key for which no
binding exists on the exchange the Broker will close the connection. This client feature
requires support for the corresponding feature by the Broker.</para>
<para>To enable or disable from the client, use the Connection URL option <link
linkend="JMS-Client-0-8-Connection-URL-ConnectionOptions-CloseWhenNoRoute"
><literal>closeWhenNoRoute</literal></link>.</para>
<para>See <ulink url="&qpidJavaBrokerBook;Java-Broker-Close-Connection-When-No-Route.html">
Closing client connections on unroutable mandatory messages</ulink> within the Java Broker
book for full details of the functioning of this feature.</para>
</section>
<section id="JMS-Client-0-8-Client-Understanding-MessageProducer-ImmediateMessage">
<title>Immediate Messages</title>
<para>This feature is defined in <ulink url="&amqpSrc;">AMQP specifications</ulink>.</para>
<para>When this feature is enabled, when publishing a message the Broker ensures that a
Consumer is attached to queue. If there is no Consumer attached to the queue, the message is
returned to the publisher's connection. The Message is returned to the application in an
asynchronous fashion using the Connection's <ulink
url="&oracleJeeDocUrl;javax/jms/ExceptionListener.html">ExceptionListener</ulink>.</para>
<para>The ExceptionListener will be invoked with a JMSException whose linked exception is an
<ulink url="JMS-Client-0-8-Appendix-Exceptions-AMQNoConsumersException"
>AMQNoConsumersException</ulink>. The returned message is available to the application by
calling AMQNoConsumersException#getUndeliveredMessage(). The ExceptionListener will be
invoked exactly once for each returned message.</para>
<para>The immediate message feature is turned <emphasis>off</emphasis> by default. It can be
enabled with system property <link
linkend="JMS-Client-0-8-System-Properties-DefaultImmediate"
><literal>qpid.default_immediate</literal></link>.</para>
</section>
<section id="JMS-Client-0-8-Client-Understanding-MessageProducer-FlowControl">
<title>Flow Control</title>
<para>With this feature, if a message is sent to a queue that is overflow, the producer's
session is blocked until the queue becomes underfull, or a timeout expires. This client
feature requires support for the corresponding feature by the Broker.</para>
<para>To control the timeout use System property <link
linkend="JMS-Client-0-8-System-Properties-FlowControlWaitFailure"
><literal>qpid.flow_control_wait_failure</literal></link>. To control the frequency with
which warnings are logged whilst a Session is blocked, use System property <link
linkend="JMS-Client-0-8-System-Properties-FlowControlWaitNotifyPeriod"
><literal>qpid.flow_control_wait_notify_period</literal></link></para>
<para>See <ulink
url="&qpidJavaBrokerBook;Java-Broker-Runtime-Disk-Space-Management.html#Qpid-Producer-Flow-Control"
> Producer Flow Control</ulink> within the Java Broker book for full details of the
functioning of this feature.</para>
</section>
</section>
<section id="JMS-Client-0-8-Client-Understanding-MessageConsumer">
<title>MessageConsumer</title>
<para>A MessageConsumer receives messages from a Queue or Topic.</para>
<para>MessageConsumer objects are created from the Session.</para>
<para>Qpid JMS MessageConsumers have a number of features above that required by JMS. These are
described in the sub-sections that follow.</para>
<section id="JMS-Client-0-8-Client-Understanding-MessageConsumer-ConsumerSideEffect">
<title>Consumers have Exchange/Queue Declaration and Binding Side Effect</title>
<para>By default, calling <ulink
url="&oracleJeeDocUrl;javax/jms/Session.html#createConsumer(javax.jms.Destination)"
>Session#createConsumer()</ulink> will cause:</para>
<orderedlist>
<listitem>
<para>If the exchange does not exist on the Broker, it will be created. The exchange is
specified by the Binding URL associated with the Destination.</para>
</listitem>
<listitem>
<para>If the queue does not exist on the Broker, it will be created. The queue is
specified by the Binding URL associated with the Destination.</para>
</listitem>
<listitem>
<para>If there is no binding between the exchange and queue, a binding will be created
using the routingkey as a bindingkey. The exchange, queue and routing key are specified
by the Binding URL associated with the Destination.</para>
</listitem>
</orderedlist>
<para>The exchange declare, queue declare and bind side effects can be suppressed using system properties
<link linkend="JMS-Client-0-8-System-Properties-DeclareExchanges"
><literal>qpid.declare_exchanges</literal></link>, <link
linkend="JMS-Client-0-8-System-Properties-DeclareQueues"
><literal>qpid.declare_queues</literal></link> and
<link linkend="JMS-Client-0-8-System-Properties-BindQueues"
><literal>qpid.bind_queues</literal></link>.</para>
</section>
<section id="JMS-Client-0-8-Client-Understanding-MessageConsumer-TopicSubscriptions">
<title>Topic Subscriptions</title>
<para>The Qpid JMS client implements each subscription to a Topic as separate queue on the
Broker. From the perspective of the JMS application this implementational detail is
irrelevant: the application never needs to directly address these queues. However, these
details are important when considering Management and Operational concerns.</para>
<para>Durable topic subscriptions use a <emphasis>durable</emphasis> and
<emphasis>exclusive</emphasis> queue named as follows:</para>
<programlisting>
clientid: + subscriptionId
</programlisting>
<para>where <literal>subscriptionId</literal> is that passed to the <ulink
url="&oracleJeeDocUrl;javax/jms/Session.html#createDurableSubscriber(javax.jms.Topic,%20java.lang.String)"
>Session#createDurableSubscriber(javax.jms.Topic,java.lang.String)</ulink></para>
<para>Calling <ulink
url="&oracleJeeDocUrl;javax/jms/Session.html#unsubscribe(java.lang.String)"
>Session#unsubscribe(java.lang.String)</ulink> deletes the underlying queue.</para>
<para>Non-durable topic subscriptions use a <emphasis>non-durable</emphasis>,
<emphasis>exclusive</emphasis> and <emphasis>auto-delete</emphasis> queue named as
follows:</para>
<programlisting>
tmp + _ + ip + _ + port + _ + sequence
</programlisting>
<para>where <literal>ip</literal> is the ip address of the client with dots replaced by
underscores, <literal>port</literal> is the ephemeral port number assigned to the client's
connection, and <literal>sequence</literal> is a sequence number.</para>
<para>Closing the consumer (or closing the connection) will delete the underlying
queue.</para>
</section>
<section id="JMS-Client-0-8-Client-Understanding-MessageConsumer-MaximumDeliveryCount">
<title>Maximum Delivery Count</title>
<para>With this feature, the Broker keeps track of a number of times a message has been
delivered to a consumer. If the count ever exceeds a threshold value, the Broker moves the
message to a dead letter queue (DLQ). This is used to prevent poison messages preventing a
system's operation. This client feature requires support for the corresponding feature by
the Broker.</para>
<para>When using this feature, the application must either set system property <link
linkend="JMS-Client-0-8-System-Properties-RejectBehaviour">qpid.reject.behaviour</link> or
the Binding URL option <link linkend="JMS-Client-0-8-Binding-URL-Options-RejectBehaviour"
><literal>rejectbehaviour</literal></link> to the value
<literal>server</literal>.</para>
<para>See <ulink
url="&qpidJavaBrokerBook;Java-Broker-Runtime-Handling-Undeliverable-Messages.html#Java-Broker-Runtime-Handling-Undeliverable-Messages-Maximum-Delivery-Count"
> Handling Undeliverable Messages</ulink> within the Java Broker book for full details of
the functioning of this feature.</para>
<note><para>The optional JMS message header <literal>JMSXDeliveryCount</literal> is <emphasis>not</emphasis>
supported.</para></note>
</section>
</section>
<section id="JMS-Client-0-8-Client-Understanding-Destinations">
<title>Destinations</title>
<para>A Destination is either a Queue or Topic. In the Qpid JMS client a Destination
encapsulates a Binding URL. In simple terms, the Binding URL comprises of an exchange, queue
and a routing key. Binding URLs are described fully by <xref
linkend="JMS-Client-0-8-Binding-URL"/>. </para>
<para>In many cases, applications do not need to deal directly with Binding URLs, instead they
can refer to JMS administered objects declared in the JNDI properties file with the
<literal>queue.</literal> and <literal>topic.</literal> prefix to create Queues and Topics
objects respectively. </para>
</section>
</chapter>
|