Skip to content

Commit f244e8b

Browse files
Add asciidocs
1 parent cd892ca commit f244e8b

12 files changed

+2529
-0
lines changed

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ DEPS_DIR = deps
99
endif
1010
endif
1111

12+
export PATH := $(CURDIR):$(CURDIR)/scripts:$(PATH)
13+
1214
MVN_FLAGS += -Ddeps.dir="$(abspath $(DEPS_DIR))"
1315

1416
.PHONY: all deps tests clean distclean
@@ -33,3 +35,7 @@ distclean: clean
3335
$(MAKE) -C $(DEPS_DIR)/rabbitmq_codegen clean
3436

3537
.PHONY: cluster-other-node
38+
39+
.PHONY: doc
40+
doc: ## Generate PerfTest documentation
41+
@mvnw asciidoctor:process-asciidoc

pom.xml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
<nexus-staging-maven-plugin.version>1.6.13</nexus-staging-maven-plugin.version>
6464
<checksum.maven.plugin.version>1.11</checksum.maven.plugin.version>
6565
<build-helper-plugin.version>3.3.0</build-helper-plugin.version>
66+
<asciidoctor.maven.plugin.version>2.2.2</asciidoctor.maven.plugin.version>
67+
<asciidoctorj.version>2.5.7</asciidoctorj.version>
6668

6769
<java.compile.version>11</java.compile.version>
6870
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -277,6 +279,40 @@
277279
</configuration>
278280
</plugin>
279281

282+
<plugin>
283+
<groupId>org.asciidoctor</groupId>
284+
<artifactId>asciidoctor-maven-plugin</artifactId>
285+
<version>${asciidoctor.maven.plugin.version}</version>
286+
<dependencies>
287+
<dependency>
288+
<groupId>org.asciidoctor</groupId>
289+
<artifactId>asciidoctorj</artifactId>
290+
<version>${asciidoctorj.version}</version>
291+
</dependency>
292+
</dependencies>
293+
<configuration>
294+
<sourceDirectory>src/docs/asciidoc</sourceDirectory>
295+
<sourceDocumentName>index.adoc</sourceDocumentName>
296+
<!-- Attributes common to all output formats -->
297+
<backend>html5</backend>
298+
<attributes>
299+
<endpoint-url>https://example.org</endpoint-url>
300+
<sourcedir>${project.build.sourceDirectory}</sourcedir>
301+
<project-version>${project.version}</project-version>
302+
<imagesdir>./images</imagesdir>
303+
<toc>left</toc>
304+
<icons>font</icons>
305+
<sectanchors>true</sectanchors>
306+
<!-- set the idprefix to blank -->
307+
<idprefix />
308+
<idseparator>-</idseparator>
309+
<docinfo1>true</docinfo1>
310+
<source-highlighter>coderay</source-highlighter>
311+
</attributes>
312+
313+
</configuration>
314+
</plugin>
315+
280316
</plugins>
281317
<extensions>
282318
<extension>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
3+
. $(pwd)/release-versions.txt
4+
5+
MESSAGE=$(git log -1 --pretty=%B)
6+
7+
git checkout -- .mvn/maven.config
8+
9+
git remote set-branches origin 'gh-pages'
10+
git fetch -v
11+
12+
git checkout gh-pages
13+
mkdir -p ${API_FAMILY}/${RELEASE_VERSION}/htmlsingle
14+
cp target/generated-docs/* ${API_FAMILY}/${RELEASE_VERSION}/htmlsingle
15+
git add ${API_FAMILY}
16+
17+
git commit -m "$MESSAGE"
18+
git push origin gh-pages

release-versions.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
RELEASE_VERSION="3.0.0.RC1"
22
DEVELOPMENT_VERSION="3.1.0-SNAPSHOT"
33
RELEASE_BRANCH="main"
4+
API_FAMILY="3.x"
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
== Implementation Details
2+
3+
This section provides additional implementation details for specific
4+
JMS API classes in the JMS Client.
5+
6+
Deviations from the specification are implemented to support common
7+
acknowledgement behaviours.
8+
9+
[#jms_topic_support]
10+
== JMS Topic Support
11+
12+
JMS topics are implemented using an AMQP link:https://rabbitmq.com/tutorials/amqp-concepts.html#exchange-topic[topic exchange]
13+
and a dedicated AMQP queue for each JMS topic subscriber. The AMQP
14+
topic exchange is `jms.temp.topic` or `jms.durable.topic`, depending
15+
on whether the JMS topic is temporary or not, respectively. Let's
16+
take an example with a subscription to a durable `my.jms.topic` JMS topic:
17+
18+
* a dedicated AMQP queue is created for this subscriber, its name
19+
will follow the pattern `+jms-cons-{UUID}+`.
20+
* the `+jms-cons-{UUID}+` AMQP queue is bound to the `jms.durable.topic`
21+
exchange with the `my.jms.topic` binding key.
22+
23+
If another subscriber subscribes to `my.jms.topic`, it will have
24+
its own AMQP queue and both subscribers will receive messages published
25+
to the `jms.durable.topic` exchange with the `my.jms.topic` routing key.
26+
27+
The example above assumes no topic selector is used when declaring the
28+
subscribers. If a topic selector is in use, a `x-jms-topic`-typed exchange
29+
will sit between the `jms.durable.topic` topic exchange and the
30+
subscriber queue. So the topology is the following when subscribing to
31+
a durable `my.jms.topic` JMS topic with a selector:
32+
33+
* a dedicated AMQP queue is created for this subscriber, its name
34+
will follow the pattern `+jms-cons-{UUID}+`.
35+
* a `x-jms-topic`-typed exchange is bound to the subscriber AMQP queue with
36+
the `my.jms.topic` binding key and some arguments related to the selector
37+
expressions. Note this exchange is scoped to the JMS session and not only
38+
to the subscriber.
39+
* the `x-jms-topic`-typed exchange is bound to the `jms.durable.topic`
40+
exchange with the `my.jms.topic` binding key.
41+
42+
Exchanges can be bound together thanks to a link:https://rabbitmq.com/e2e.html[RabbitMQ extension].
43+
Note the <<enable_topic_selector, Topic Selector Plugin>> must be enabled for topic selectors
44+
to work.
45+
46+
== QueueBrowser Support
47+
48+
=== Overview of queue browsers
49+
50+
The JMS API includes objects and methods to browse an existing queue
51+
destination, reading its messages _without_ removing them from the
52+
queue. Topic destinations cannot be browsed in this manner.
53+
54+
A `QueueBrowser` can be created from a (queue) `Destination`,
55+
with or without a selector expression. The browser has a `getEnumeration()`
56+
method, which returns a Java `Enumeration` of ``Message``s copied from
57+
the queue.
58+
59+
If no selector is supplied, then all messages in the queue appear
60+
in the `Enumeration`. If a selector is supplied, then only those
61+
messages that satisfy the selector appear.
62+
63+
=== Implementation
64+
65+
The destination queue is read when the `getEnumeration()` method is
66+
called. A _snapshot_ is taken of the messages in the queue; and the
67+
selector expression, if one is supplied, is used at this time to discard
68+
messages that do not match.
69+
70+
The message copies may now be read using the `Enumeration` interface
71+
(`nextElement()` and `hasMoreElements()`).
72+
73+
The selector expression and the destination queue of the `QueueBrowser`
74+
may not be adjusted after the `QueueBrowser` is created.
75+
76+
An `Enumeration` cannot be "reset", but the `getEnumeration()` method
77+
may be re-issued, taking a _new_ snapshot from the queue each time.
78+
79+
The contents of an `Enumeration` survive session and/or connection
80+
close, but a `QueueBrowser` may not be used after the session that
81+
created it has closed. `QueueBrowser.close()` has no effect.
82+
83+
==== Which messages are included
84+
85+
Messages that arrive, expire, are re-queued, or are removed after
86+
the `getEnumeration()` call have no effect on the contents of the
87+
`Enumeration` it produced. If the messages in the queue change
88+
_while the_ `Enumeration` _is being built_, they may or may not be
89+
included. In particular, if messages from the queue are simultaneously
90+
read by another client (or session), they may or may not appear in
91+
the `Enumeration`.
92+
93+
Message copies do not "expire" from an `Enumeration`.
94+
95+
==== Order of messages
96+
97+
If other client sessions read from a queue that is being browsed,
98+
then it is possible that some messages may subsequently be received out
99+
of order.
100+
101+
Message order will not be disturbed if no other client sessions read
102+
the queue at the same time.
103+
104+
==== Memory usage
105+
106+
When a message is read from the `Enumeration` (with `nextElement()`),
107+
then no reference to it is retained in the Java Client. This means the
108+
storage it occupies in the client is eligible for release
109+
(by garbage collection) if no other references are retained.
110+
Retaining an `Enumeration` will retain the storage for all message
111+
copies that remain in it.
112+
113+
If the queue has many messages -- or the messages it contains are very
114+
large -- then a `getEnumeration()` method call may consume a large
115+
amount of memory in a very short time. This remains true even if only
116+
a few messages are selected. There is currently limited protection
117+
against `OutOfMemoryError` conditions that may arise because of this.
118+
See the next section.
119+
120+
==== Setting a maximum number of messages to browse
121+
122+
Each connection is created with a limit on the number of messages that
123+
are examined by a `QueueBrowser`. The limit is set on the
124+
`RMQConnectionFactory` by `RMQConnectionFactory.setQueueBrowserReadMax(int)`
125+
and is passed to each `Connection` subsequently created
126+
by `ConnectionFactory.createConnection()`.
127+
128+
The limit is an integer that, if positive, stops the queue browser from
129+
reading more than this number of messages when building an enumeration.
130+
If it is zero or negative, it is interpreted as imposing no limit on
131+
the browser, and all of the messages on the queue are scanned.
132+
133+
The default limit for a factory is determined by the
134+
`rabbit.jms.queueBrowserReadMax` system property, if set, and the value
135+
is specified as `0` if this property is not set or is not an integer.
136+
137+
If a `RMQConnectionFactory` value is obtained from a JNDI provider,
138+
then the limit set when the factory object was created is preserved.
139+
140+
==== Release Support
141+
142+
Support for ``QueueBrowser``s is introduced in the JMS Client 1.2.0.
143+
Prior to that release, calling `Session.createBrowser(Queue queue[, String selector])`
144+
resulted in an `UnsupportedOperationException`.
145+
146+
=== Group and individual acknowledgement
147+
148+
Prior to version 1.2.0 of the JMS client, in client acknowledgement mode
149+
(`Session.CLIENT_ACKNOWLEDGE`), acknowledging any message from an open
150+
session would acknowledge _every_ unacknowledged message of that session,
151+
whether they were received before or after the message being acknowledged.
152+
153+
Currently, the behaviour of `Session.CLIENT_ACKNOWLEDGE` mode is
154+
modified so that, when calling `msg.acknowledge()`, only the message
155+
`msg` _and all_ previously received _unacknowledged messages on that
156+
session_ are acknowledged. Messages received _after_ `msg` was received
157+
are not affected. This is a form of _group acknowledgement_,
158+
which differs slightly from the JMS specification but is likely to
159+
be more useful, and is compatible with the vast majority of uses of
160+
the existing acknowledge function.
161+
162+
For even finer control, a new acknowledgement mode may be set when
163+
creating a session, called `RMQSession.CLIENT_INDIVIDUAL_ACKNOWLEDGE`.
164+
165+
A session created with this acknowledgement mode will mean that messages
166+
received on that session will be acknowledged individually. That is,
167+
the call `msg.acknowledge()` will acknowledge only the message `msg`
168+
and not affect any other messages of that session.
169+
170+
The acknowledgement mode `RMQSession.CLIENT_INDIVIDUAL_ACKNOWLEDGE`
171+
is equivalent to `Session.CLIENT_ACKNOWLEDGE` in all other respects.
172+
In particular the `getAcknowledgeMode()` method returns
173+
`Session.CLIENT_ACKNOWLEDGE` even if
174+
`RMQSession.CLIENT_INDIVIDUAL_ACKNOWLEDGE` has been set.
175+
176+
== Arbitrary Message support
177+
178+
Any instance of a class that implements the `javax.jms.Message`
179+
interface can be _sent_ by a JMS message producer.
180+
181+
All properties of the message required by `send()` are correctly
182+
interpreted except that the `JMSReplyTo` header and objects
183+
(as property values or the body of an `ObjectMessage`) that
184+
cannot be deserialized are ignored.
185+
186+
The implementation extracts the properties and body from the `Message`
187+
instance using interface methods and recreates it as a message of
188+
the right (`RMQMessage`) type (`BytesMessage`, `MapMessage`, `ObjectMessage`,
189+
`TextMessage`, or `StreamMessage`) before sending it. This means
190+
that there is some performance loss due to the copying; but in the
191+
normal case, when the message is an instance of
192+
`com.rabbitmq.jms.client.RMQMessage`, no copying is done.

src/docs/asciidoc/index.adoc

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
= RabbitMQ JMS Client
2+
:revnumber: {project-version}
3+
:example-caption!:
4+
ifndef::imagesdir[:imagesdir: images]
5+
ifndef::sourcedir[:sourcedir: ../../main/java]
6+
:source-highlighter: prettify
7+
8+
== Introduction
9+
10+
RabbitMQ is not a JMS provider but includes https://github.com/rabbitmq/rabbitmq-server/tree/v3.9.x/deps/rabbitmq_jms_topic_exchange[a plugin]
11+
needed to support the JMS Queue and Topic messaging models. JMS Client
12+
for RabbitMQ implements the JMS specification on top of the
13+
link:https://rabbitmq.com/api-guide.html[RabbitMQ Java client], thus allowing new and
14+
existing JMS applications to connect to RabbitMQ.
15+
16+
The library supports JMS 2.0 as of 2.7.0 and JMS 3.0 as of 3.0.0.
17+
18+
The plugin and the JMS client are meant to work and be used together.
19+
20+
See the link:https://rabbitmq.com/java-versions.html[RabbitMQ Java libraries support page] for the support timeline
21+
of the RabbitMQ JMS Client library.
22+
23+
24+
== Components
25+
26+
To fully leverage JMS with RabbitMQ, you need the following components:
27+
28+
* the https://github.com/rabbitmq/rabbitmq-jms-client[JMS client library] and its dependent libraries.
29+
* https://github.com/rabbitmq/rabbitmq-server/tree/v3.9.x/deps/rabbitmq_jms_topic_exchange[RabbitMQ JMS topic selector plugin] that is included
30+
with RabbitMQ starting with version 3.6.3. To support message selectors for JMS
31+
topics, the RabbitMQ Topic Selector plugin must be installed on the
32+
RabbitMQ server. Message selectors allow a JMS application to filter
33+
messages using an expression based on SQL syntax. Message selectors
34+
for Queues are not currently supported.
35+
36+
== JMS and AMQP 0-9-1
37+
38+
JMS is the standard messaging API for the JEE platform. It is
39+
available in commercial and open source implementations. Each
40+
implementation includes a JMS provider, a JMS client library, and
41+
additional, implementation-specific components for administering the
42+
messaging system. The JMS provider can be a standalone implementation
43+
of the messaging service, or a bridge to a non-JMS messaging system.
44+
45+
The JMS client API is standardized, so JMS applications are portable
46+
between vendors`' implementations. However, the underlying messaging
47+
implementation is unspecified, so there is no interoperability between
48+
JMS implementations. Java applications that want to share messaging
49+
must all use the same JMS implementation unless bridging technology
50+
exists. Furthermore, non-Java applications cannot access JMS without a
51+
vendor-specific JMS client library to enable interoperability.
52+
53+
AMQP 0-9-1 is a messaging protocol, rather than an API like JMS. Any
54+
client that implements the protocol can access a broker that supports
55+
AMQP 0-9-1. Protocol-level interoperability allows AMQP 0-9-1 clients
56+
written in any programming language and running on any operating
57+
system to participate in the messaging system with no need to bridge
58+
incompatible vendor implementations.
59+
60+
Because JMS Client for RabbitMQ is implemented using the RabbitMQ Java
61+
client, it is compliant with both the JMS API and the AMQP 0-9-1 protocol.
62+
63+
You can download the JMS 2.0 specification and API documentation from
64+
the https://download.oracle.com/otndocs/jcp/jms-2_0_rev_a-mrel-eval-spec/index.html[Oracle Technology Network Web site].
65+
66+
== Limitations
67+
68+
Some JMS 1.1 and 2.0 features are unsupported in the RabbitMQ JMS Client:
69+
70+
* The JMS Client does not support server sessions.
71+
* XA transaction support interfaces are not implemented.
72+
* Topic selectors are supported with the RabbitMQ JMS topic selector
73+
plugin. Queue selectors are not yet implemented.
74+
* SSL and socket options for RabbitMQ connections are supported, but
75+
only using the (default) SSL connection protocols that the RabbitMQ client provides.
76+
* The JMS `NoLocal` subscription feature, which prevents delivery of
77+
messages published from a subscriber's own connection, is not supported
78+
with RabbitMQ. You can call a method that includes the `NoLocal`
79+
argument, but it is ignored.
80+
81+
See link:jms-client-compliance.md[the JMS API compliance documentation] for a
82+
detailed list of supported JMS APIs.
83+
84+
include::installation.adoc[]
85+
include::interoperability.adoc[]
86+
include::logging.adoc[]
87+
include::publisher-confirm.adoc[]
88+
include::rpc.adoc[]
89+
include::implementation-details.adoc[]
90+
91+
== Further Reading
92+
93+
To gain better understanding of AMQP 0-9-1 concepts and interoperability of
94+
the RabbitMQ JMS client with AMQP 0-9-1 clients, you may wish to read an
95+
link:https://rabbitmq.com/tutorials/amqp-concepts.html[Introduction to RabbitMQ Concepts]
96+
and browse our
97+
link:amqp-0-9-1-quickref.html[AMQP 0-9-1 Quick Reference Guide].

0 commit comments

Comments
 (0)