JMS Swiftlet
JMS Implementation
The JMS Swiftlet implements the JMS 1.1 specification.
Queue Location Dependency
Queues are the base for the Point-To-Point message model. This model is usually taken to implement server inbound queues. Queues are location-dependent. They reside on a specific router, usually for a long time. Sending messages to a queue could be performed from every router in a network that has a route to the router where the queue is hosted. Receiving messages from a queue is limited to the queue's hosting router. It is not possible to create a QueueReceiver
for a queue on a different router.
Multiple Queue Receivers
Usually, a queue has one receiver that fetches and processes the messages. SwiftMQ permits the creation of multiple receivers per queue. With this approach, a 'natural' round-robin scheduling takes place where each receiver fetches the next available message from the top of the queue. This means that a load balancing on the client side could be easily implemented by simply starting more client process instances to increase the message throughput.
Queue Names
Due to location dependency, a queue name must always be completely qualified to ensure correct message routing:
<queue>@<routername>
An exception to this rule, the initial definition of queues in the Queue Manager configuration must always be without the router name. This makes it easy to change it. For this reason, it is suggested to define a JNDI alias for queues to avoid definitions of router names in JMS applications.
Predefined Queue unrouteable
There is one predefined queue on each router for messages that cannot be routed to their destination queue because the queue is dropped while the message is traveling the router network. These messages become unrouteable and will be forwarded to the queue unrouteable
on the specific router. To get these messages, a JMS application can create a QueueReceiver and send them again e. g. with a new destination.
Predefined Queue routerdlq
The predefined queue routerdlq
is the router's dead-letter queue and serves as a destination for expired messages if the Queue Manager's job Queue Cleanup DLQ
is used. See the Queue Manager Swiftlet documentation.
Predefined Topic swiftmq.jndi
There is one predefined topic that is shared between JMS clients and internal SwiftMQ Swiftlets; the topic to broadcast JNDI lookups, the use of which is restricted to SwiftMQ's JNDI implementation. The topic name is swiftmq.jndi
. To use this topic, a publish-grant is needed. This could simply be done by defining this grant within the public group. For details have a look at the Authentication Swiftlet configuration.
Topic Location Independency
In contrast to queues (PTP message model), topics are location-independent. They are available on every router in a connected router network due to automatic broadcasts of local subscribers from every router to all connected routers in the network. In fact, one can publish or subscribe from any router in a router network if the authentication process on the specific local router was successful.
Topic Hierarchy
SwiftMQ provides the possibility to define topic hierarchies in the form <roottopic>.<subtopic>.<subsubtopic> etc.
Example:
iit.sales.EU
iit.sales.US
iit.projects.swiftmq.users
news.weather.forecasts
sports.formula1.MichaelSchumacher
Copy
Publishing and subscribing rules to nodes in a hierarchy:
Selecting a specific node in a topic hierarchy publishes messages to the addressed node and all concerning sub-nodes. Example: publishing to node
iit.sales
send the messages also toiit.sales
,iit.sales.US
,iit.sales.EU
.Subscribing to a specific node in a topic hierarchy means receiving all messages addressed to this node and all parent and sub-nodes. Example: subscribing to
iit.sales.US
one receives all messages published iniit
,iit.sales
, andiit.sales.US
; subscribing toiit.sales
one receives all messages published iniit
,iit.sales
,iit.sales.US
,iit.sales.EU
, but you don't receive the messages published in theiit.projects
hierarchy.A subscriber receives a message only once, regardless of the number of topics his subscription matches.
SQL-Like Predicate Topic Addressing
As an extension to the normal topic node- and subnode-addressing scheme, SwiftMQ provides SQL-Like predicate topic addresses. So every specified subnode could be a SQL-Like predicate. A SQL-Like predicate could contain wildcards that match a single character (the underscore '_'), or any characters (the percent sign '%'). The escape character is '\'.
Example:
To address the topic iit.sales.US
one can also write iit.s%s._S
; to address all subnodes within the same hierarchy level on hierarchy iit
concerning swiftmq
the predicate is iit.%.swiftmq
.
Root nodes cannot be addressed as a predicate; i. e. it is not possible to specify i%.%.swiftmq
.
Predicate topics are normal topic destinations and are not available via JNDI lookups. To create a predicate topic, one has to use the createTopic()
method from a TopicSession
.
Example:
Topic allSwiftMQ = topicSession.createTopic("iit.%.swiftmq");
msg.setJMSDestination(allSwiftMQ);
publisher.publish(msg);
Access to predicate topics must be granted by the Authentication Swiftlet just like normal topics.
Durable Subscribers
Durable Subscribers (Programmatically)
The JMS specification may be unclear concerning the creation, reconnection, change, and deletion of durable subscribers. So let's have a look at how it works in reality:
Creating a durable subscriber:
A valid client id must be set with
setClientID()
as the first method call after creating a connection or the client id has to be preset within the connection factory.A
TopicSession
must be created.Choose one of the
createDurableSubscriber()
methods.The durable subscriber is now in place and receives all the messages addressed to this topic.
Reconnect to an existing durable subscriber:
Same procedure as above; supply the same parameters to
createDurableSubscriber()
.
Changing an existing durable subscriber:
Same procedure as above, but supply different parameters on
createDurableSubriber()
(except the durable subscriber name, which must match, otherwise a new one is created).The durable subscriber will be dropped with all content and re-created with the new parameters.
Deleting an existing durable subscriber:
A valid client id must be set with
setClientID()
as the first method call after creating a connection or the client id has to be preset within the connection factory.A
TopicSession
must be created.The
unsubscribe()
method must be called with the name of the durable subscriber.The durable subscriber will be dropped with all content.
Durable subscribers are location-dependent. They reside on a specific router and can only be accessed from that router on which they have been created.
Durable Subscribers (Administratively)
Durable subscribers can be created and removed administratively via SwiftMQ Explorer App or CLI.
To create a durable subscriber with SwiftMQ Explorer App, select the node Active Durable Topic Subscribers
of the Topic Manager Swiftlet's Usage
folder:
Click on Create a new Entity
:
The Name
has to of <clientid>$<durablename>
. Bound To
will be set from SwiftMQ during the creation of the durable subscriber and contains its queue name. After pushing the Create
button, the durable subscriber is created and can be used by JMS clients:
To remove an existing durable subscriber with SwiftMQ Explorer, select its entry and click on Delete Entity
and the durable subscriber will be removed:
Vendor Message Properties
JMS provides the possibility to specify vendor-specific message properties. These properties have the prefix JMS_<vendor>
. SwiftMQ defines the following vendor properties:
Property Name | Type | Content |
---|---|---|
| String | Contains the client id of the message producer. |
| String | Contains the reason for unroutable messages. |
JMS Examples
The SwiftMQ distribution contains a directory "samples" with various example programs. To use it, please consult the Readme.txt stored in the "samples" directory.
Thread Pools
The JMS Swiftlet uses the following thread pools:
jms.connection
jms.session
jms.connection
This thread pool is shared from all JMS connections at the router side and used for outbound writes from the router to JMS clients. These outbound writes are actually very short running tasks and a single thread of thread pool jms.connection
can handle hundreds of connections. However, if there are slow network connections or if large messages are being transferred, the thread blocks until the outbound write have been completed and other writes are stacked up and have to wait. The default setting for this pool is min-threads=5, max-threads=5. It ensures that there are always free threads, even when the above conditions occur. The max-threads attribute should be increased when all threads of this pool are continuously busy.
jms.session
This thread pool is shared from all JMS sessions on the router side. In fact, all JMS work will be done from this pool. The work is scheduled as a so-called async task that is dispatched into this pool. These tasks are actually short running so a thread from this pool will not block. The only exceptions are persistent operations, e.g. large messages stored via the JDBC Store Swiftlet. This can take time and a thread will block until the operation has been finished. The default setting for this pool is min-threads=5, max-threads=5. It ensures that there are always free threads, even when the above conditions occur. The max-threads attribute should be increased when all threads of this pool are continuously busy.
Configuration
The configuration of the JMS Swiftlet is defined within the element
<swiftlet name="sys$jms" .../>
of the router's configuration file.
Attributes of Element "swiftlet"
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
allow-same-clientid | java.lang.Boolean | No | Allows multiple connection with the same JMS Client Id if set to true |
collect-interval | java.lang.Long | No | Collect Interval Messages/Sec |
max-connections | java.lang.Integer | No | Maximum JMS Connections |
consumer-cache-low-water-mark | java.lang.Integer | No | Consumer caches are refilled when reaching this mark |
crfactory-class | java.lang.String | No | Challenge/Response Factory Class |
Values
Attribute | Values |
---|---|
allow-same-clientid | Default: false |
collect-interval | Default: 10000 |
max-connections | Default: -1 |
consumer-cache-low-water-mark | Min: 0 |
crfactory-class | Default: com.swiftmq.auth.ChallengeResponseFactoryImpl |
Element List "intravm-connection-factories", Parent Element: "swiftlet"
IntraVM Connection Factories. This element list contains zero or more "intravm-connection-factory" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this IntraVM Connection Factory |
smqp-producer-reply-interval | java.lang.Integer | Yes | Number of SMQP Requests after which a SMQP Reply is required |
smqp-consumer-cache-size | java.lang.Integer | Yes | Cache Size per Consumer (Messages) |
smqp-consumer-cache-size-kb | java.lang.Integer | Yes | Cache Size per Consumer (KB) |
jms-client-id | java.lang.String | No | JMS Client Id for durable Subscribers |
jms-default-delivery-mode | java.lang.String | Yes | JMS Default Delivery Mode |
jms-default-message-ttl | java.lang.Long | Yes | JMS Default Message TTL |
jms-default-message-priority | java.lang.Integer | Yes | JMS Default Message Priority |
jms-default-message-id-enabled | java.lang.Boolean | No | JMS Default Message Id Enabled |
jms-default-message-timestamp-enabled | java.lang.Boolean | No | JMS Default Message Timestamp Enabled |
thread-context-classloader-for-getobject | java.lang.Boolean | No | Use the Thread Context Classloader for getObject() |
Values
Attribute | Values |
---|---|
smqp-producer-reply-interval | Min: 1 |
smqp-consumer-cache-size | Min: 1 |
smqp-consumer-cache-size-kb | Default: 2048 |
jms-client-id | |
jms-default-delivery-mode | Choice: persistent non_persistent |
jms-default-message-ttl | Min: 0 |
jms-default-message-priority | Min: 0 |
jms-default-message-id-enabled | Default: true |
jms-default-message-timestamp-enabled | Default: true |
thread-context-classloader-for-getobject | Default: false |
Element List "listeners", Parent Element: "swiftlet"
Listener Definitions. This element list contains zero or more "listener" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Listener |
connectaddress | java.lang.String | No | Listener Connect IP Address for NAT |
connectport | java.lang.Integer | No | Listener Connect Port for NAT |
bindaddress | java.lang.String | No | Listener Bind IP Address |
port | java.lang.Integer | Yes | Listener Port |
hostname2 | java.lang.String | No | Hostname of the 2nd HA Instance |
connectaddress2 | java.lang.String | No | Listener Connect IP Address for NAT of the 2nd HA Instance |
connectport2 | java.lang.Integer | No | Listener Connect Port for NAT of the 2nd HA Instance |
bindaddress2 | java.lang.String | No | Listener Bind IP Address of the 2nd HA Instance |
port2 | java.lang.Integer | No | Listener Port 2nd HA Instance of the 2nd HA Instance |
use-tcp-no-delay | java.lang.Boolean | Yes | Use Tcp No Delay |
socketfactory-class | java.lang.String | No | Listener Socketfactory Class |
keepalive-interval | java.lang.Long | No | Interval for sending Keep Alive Messages |
max-connections | java.lang.Integer | No | Maximum JMS Connections for this Listener |
router-input-buffer-size | java.lang.Integer | No | Router Network Input Buffer Size |
router-input-extend-size | java.lang.Integer | No | Router Network Input Extend Size |
router-output-buffer-size | java.lang.Integer | No | Router Network Output Buffer Size |
router-output-extend-size | java.lang.Integer | No | Router Network Output Extend Size |
Values
Attribute | Values |
---|---|
connectaddress | |
connectport | Default: -1 |
bindaddress | |
port | |
hostname2 | |
connectaddress2 | |
connectport2 | Default: -1 |
bindaddress2 | |
port2 | Default: -1 |
use-tcp-no-delay | Default: true |
socketfactory-class | Default: com.swiftmq.net.PlainSocketFactory |
keepalive-interval | Default: 60000 |
max-connections | Default: -1 |
router-input-buffer-size | Min: 4096 |
router-input-extend-size | Min: 4096 |
router-output-buffer-size | Min: 4096 |
router-output-extend-size | Min: 4096 |
Element List "host-access-list", Parent Element: "listener"
Host Access List. This element list contains zero or more "host-access-entry" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Host Access Entry |
Element List "connection-factories", Parent Element: "listener"
Connection Factories. This element list contains zero or more "connection-factory" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Connection Factory |
reconnect-enabled | java.lang.Boolean | No | Reconnect Enabled |
reconnect-max-retries | java.lang.Integer | No | Maximum Retries for Reconnect |
reconnect-delay | java.lang.Long | No | Reconnect Delay in ms |
duplicate-message-detection | java.lang.Boolean | No | Enables Duplicate Message Detection for Consumers |
duplicate-backlog-size | java.lang.Integer | No | Max. Number of Entries of JMS Message IDs in the Duplicate Backlog |
client-input-buffer-size | java.lang.Integer | No | Client Network Input Buffer Size |
client-input-extend-size | java.lang.Integer | No | Client Network Input Extend Size |
client-output-buffer-size | java.lang.Integer | No | Client Network Output Buffer Size |
client-output-extend-size | java.lang.Integer | No | Client Network Output Extend Size |
smqp-producer-reply-interval | java.lang.Integer | Yes | Number of SMQP Requests after which a SMQP Reply is required |
smqp-consumer-cache-size | java.lang.Integer | Yes | Cache Size per Consumer (Messages) |
smqp-consumer-cache-size-kb | java.lang.Integer | Yes | Cache Size per Consumer (KB) |
jms-client-id | java.lang.String | No | JMS Client Id for durable Subscribers |
jms-default-delivery-mode | java.lang.String | Yes | JMS Default Delivery Mode |
jms-default-message-ttl | java.lang.Long | Yes | JMS Default Message TTL |
jms-default-message-priority | java.lang.Integer | Yes | JMS Default Message Priority |
jms-default-message-id-enabled | java.lang.Boolean | No | JMS Default Message Id Enabled |
jms-default-message-timestamp-enabled | java.lang.Boolean | No | JMS Default Message Timestamp Enabled |
thread-context-classloader-for-getobject | java.lang.Boolean | No | Use the Thread Context Classloader for getObject() |
Values
Attribute | Values |
---|---|
reconnect-enabled | Default: true |
reconnect-max-retries | Default: 10 |
reconnect-delay | Default: 10000 |
duplicate-message-detection | Default: true |
duplicate-backlog-size | Default: 2000 |
client-input-buffer-size | Min: 4096 |
client-input-extend-size | Min: 4096 |
client-output-buffer-size | Min: 4096 |
client-output-extend-size | Min: 4096 |
smqp-producer-reply-interval | Min: 1 |
smqp-consumer-cache-size | Min: 1 |
smqp-consumer-cache-size-kb | Default: 2048 |
jms-client-id | |
jms-default-delivery-mode | Choice: persistent non_persistent |
jms-default-message-ttl | Min: 0 |
jms-default-message-priority | Min: 0 |
jms-default-message-id-enabled | Default: true |
jms-default-message-timestamp-enabled | Default: true |
thread-context-classloader-for-getobject | Default: false |
Element List "usage", Parent Element: "swiftlet"
Active JMS Connections. This element list contains zero or more "usage" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Active JMS Connection |
version | java.lang.Integer | No | Version |
clientid | java.lang.String | No | Client Id |
username | java.lang.String | No | User Name |
logintime | java.lang.String | No | Login Time |
msgs-received | java.lang.Integer | No | Messages/Sec received from Client |
msgs-sent | java.lang.Integer | No | Messages/Sec sent from Client |
total-received | java.lang.Integer | No | Total Number of Messages received from Connection |
total-sent | java.lang.Integer | No | Total Number of Messages sent from Connection |
Values
Attribute | Values |
---|---|
version | |
clientid | |
username | |
logintime | |
msgs-received | Default: 0 |
msgs-sent | Default: 0 |
total-received | Default: 0 |
total-sent | Default: 0 |
Element List "tempqueues", Parent Element: "usage"
Temporary Queues created by this Connection. This element list contains zero or more "tempqueue" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Temporary Queue |
Element List "sessions", Parent Element: "usage"
JMS Sessions created by this Connection. This element list contains zero or more "tempqueue" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this JMS Session |
transacted | java.lang.Boolean | No | Transacted JMS Session |
acknowledgemode | java.lang.String | No | Acknowledge Mode |
Values
Attribute | Values |
---|---|
transacted | Default: false |
acknowledgemode | Choice: AUTO_ACKNOWLEDGE CLIENT_ACKNOWLEDGE DUPS_OK_ACKNOWLEDGE |
Element List "receiver", Parent Element: "tempqueue"
Queue Receivers created by this Session. This element list contains zero or more "receiver" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Queue Receiver |
queue | java.lang.String | No | Queue Name |
selector | java.lang.String | No | Message Selector |
Values
Attribute | Values |
---|---|
queue | |
selector |
Element List "browser", Parent Element: "tempqueue"
Queue Browsers created by this Session. This element list contains zero or more "browser" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Queue Browser |
queue | java.lang.String | No | Queue Name |
selector | java.lang.String | No | Message Selector |
Values
Attribute | Values |
---|---|
queue | |
selector |
Element List "sender", Parent Element: "tempqueue"
Queue Senders created by this Session. This element list contains zero or more "sender" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Queue Sender |
queue | java.lang.String | No | Queue Name |
Values
Attribute | Values |
---|---|
queue |
Element List "publisher", Parent Element: "tempqueue"
Topic Publishers created by this Session. This element list contains zero or more "publisher" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Topic Publisher |
topic | java.lang.String | No | Topic Name |
Values
Attribute | Values |
---|---|
topic |
Element List "durables", Parent Element: "tempqueue"
Durable Topic Subscriber created by this Session. This element list contains zero or more "durables" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Durable Topic Subscriber |
durablename | java.lang.String | No | Name of the durable Subscriber |
clientid | java.lang.String | No | Client Id |
topic | java.lang.String | No | Topic Name |
selector | java.lang.String | No | Message Selector |
nolocal | java.lang.Boolean | No | Receives no local published Messages |
boundto | java.lang.String | No | Is bound to Queue |
Values
Attribute | Values |
---|---|
durablename | |
clientid | |
topic | |
selector | |
nolocal | Default: false |
boundto |
Element List "subscriber", Parent Element: "tempqueue"
Topic Subscriber created by this Session. This element list contains zero or more "subscriber" elements with this template definition:
Definition
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | java.lang.String | Yes | Name of this Topic Subscriber |
clientid | java.lang.String | No | Client Id |
topic | java.lang.String | No | Topic Name |
selector | java.lang.String | No | Message Selector |
nolocal | java.lang.Boolean | No | Receives no local published Messages |
temptopic | java.lang.Boolean | No | Is Temporary Topic |
boundto | java.lang.String | No | Is bound to Queue |
Values
Attribute | Values |
---|---|
clientid | |
topic | |
selector | |
nolocal | Default: false |
temptopic | Default: false |
boundto |