JMS Swiftlet
Overview
The JMS Swiftlet implements the core Java Message Service (JMS) protocol support for SwiftMQ routers, enabling JMS clients to connect, authenticate, and interact with queues and topics. It manages client connections, sessions, producers, consumers, and provides mechanisms for message delivery, acknowledgment, transactions, and durable subscriptions. The Swiftlet also exposes configuration for connection factories, listeners, and connection/session resource limits.
Features
JMS Connection Management
The JMS Swiftlet manages all incoming JMS client connections, enforcing resource limits and handling authentication via a pluggable challenge/response mechanism. Each connection is tracked and can be limited globally or per-listener using the max-connections property. The Swiftlet ensures that each JMS client ID is unique by default, but this can be relaxed via the allow-same-clientid property. Connections are monitored for activity and can be disconnected if keep-alive intervals are exceeded.
Client ID Enforcement
By default, only one connection per JMS client ID is allowed. This prevents duplicate client IDs across connections, which is a JMS requirement. The allow-same-clientid property can be set to true to permit multiple connections using the same client ID, which may be useful in certain failover or testing scenarios.
Authentication and Challenge/Response
Authentication is performed using a configurable challenge/response factory, specified by the crfactory-class property. This allows integration with custom authentication mechanisms.
Per-Listener Resource Limits
Each listener can specify its own max-connections property, limiting the number of concurrent connections accepted on that listener.
Configuration Example:
<swiftlet name="sys$jms" allow-same-clientid="true" max-connections="100" crfactory-class="com.example.CustomCRFactory"/>
Listener and Connection Factory Configuration
Listeners define network endpoints (IP/port) on which the JMS Swiftlet accepts client connections. Each listener can have multiple connection factories, which define client connection parameters such as buffer sizes, reconnect behavior, and default JMS message properties. Host access lists can be set per listener to restrict which remote hosts may connect. Connection factories are registered in JNDI for client lookup.
High Availability (HA) Support
Listeners and connection factories support configuration for a secondary (HA) instance, including alternate hostnames and ports, allowing clients to failover between primary and secondary endpoints.
Host Access Control
Each listener can define a host-access-list to restrict inbound connections to specific hosts or address patterns.
Configuration Example:
<swiftlet name="sys$jms">
<listeners>
<listener name="listener1" port="4001">
<host-access-list>
<host-access-entry name="192.168.1.%"/>
</host-access-list>
<connection-factories>
<connection-factory name="cf1" smqp-consumer-cache-size="1000" reconnect-enabled="false"/>
</connection-factories>
</listener>
</listeners>
</swiftlet>
JMS Session, Producer, and Consumer Lifecycle
For each active connection, the JMS Swiftlet manages the lifecycle of JMS sessions, producers, and consumers. Sessions can be transacted or non-transacted, and support all standard JMS acknowledgment modes. Producers and consumers are tracked per session, and resource limits are enforced. Consumers can use message selectors for filtering, and both queue and topic semantics are supported.
Queue and Topic Support
Sessions can create producers and consumers for both queues and topics, including temporary destinations. Topic subscriptions support both non-durable and durable modes.
Message Selectors
Consumers and browsers can specify SQL-like message selectors to filter messages. Selectors are compiled and validated at consumer creation.
Temporary Queues and Durable Subscriptions
JMS clients can create temporary queues for the lifetime of their connection. The Swiftlet manages the lifecycle of these queues, ensuring they are deleted when the connection closes. Durable topic subscriptions are supported, with queues named according to the <clientId>$<durableName> pattern.
Temporary Queue Naming
Temporary queues are named using the pattern tmp$<sequence>-<startuptime>, ensuring uniqueness per router instance.
Durable Subscription Queues
Durable subscriptions are backed by queues named <clientId>$<durableName>, allowing persistent delivery of topic messages to offline subscribers.
Queue Browsers and Message Selectors
The JMS Swiftlet supports queue browsers, allowing clients to browse messages on a queue without consuming them. Browsers can use message selectors to filter which messages are visible during browsing sessions.
Browser Entity Tracking
Browsers are tracked per session, and their lifecycle is managed by the Swiftlet. Each browser is associated with a unique ID and can be closed independently.
Transactional Message Processing
The JMS Swiftlet fully supports JMS transactions for both queue and topic sessions. The transaction manager coordinates commit and rollback operations, ensuring atomic delivery and acknowledgment of messages. Producers and consumers enlisted in a session's transaction are managed together, and the Swiftlet handles resource cleanup and recovery in case of rollback or failover.
Composite Store Transactions
For persistent messages, the transaction manager uses composite store transactions to ensure atomicity across multiple queues.
Connection and Message Statistics
The Swiftlet collects and exposes statistics such as messages sent/received per connection, as well as total message counts. The collection interval is configurable via the collect-interval property. These statistics are available for monitoring and management purposes.
Dynamic Usage Entities
Active connections and their sessions, producers, and consumers are represented as dynamic entities under the usage entity list, providing real-time visibility into JMS activity.
Configuration Example:
<swiftlet name="sys$jms" collect-interval="2000"/>
Internal Queue Naming
tmp$<sequence>-<startuptime>— Temporary queue created for a JMS connection; used for temporary destinations.<clientId>$<durableName>— Queue backing a durable topic subscription for a given client ID and durable name.
Configuration Guide
Restricting Connections to Specific Hosts
To limit which remote hosts can connect to a JMS listener, use the host-access-list to specify allowed address patterns. This is useful for security or network segmentation.
- Edit the routerconfig.xml and locate the desired listener under the sys$jms swiftlet.
- Add host-access-entry elements with the desired address patterns (e.g., 192.168.1.% for a subnet).
- Restart the router or reload configuration if necessary.
<swiftlet name="sys$jms">
<listeners>
<listener name="listener1" port="4001">
<host-access-list>
<host-access-entry name="192.168.1.%"/>
<host-access-entry name="10.0.0.5"/>
</host-access-list>
</listener>
</listeners>
</swiftlet>
Configuring a Custom Challenge/Response Authentication Factory
To integrate a custom authentication mechanism for JMS clients, set the crfactory-class property to your implementation. This allows the Swiftlet to use your class for challenge/response authentication.
- Implement a class that extends the ChallengeResponseFactory interface.
- Set the crfactory-class property in the sys$jms swiftlet configuration to the fully qualified class name.
- Restart the router to apply the change.
<swiftlet name="sys$jms" crfactory-class="com.example.CustomCRFactory"/>
Limiting the Number of JMS Connections
To prevent resource exhaustion, set global or per-listener limits on the number of concurrent JMS connections.
- Set the max-connections property on the sys$jms swiftlet for a global limit.
- Alternatively, set the max-connections property on individual listeners for per-listener limits.
- Save the configuration and restart the router if required.
<swiftlet name="sys$jms" max-connections="50">
<listeners>
<listener name="listener1" port="4001" max-connections="10"/>
</listeners>
</swiftlet>
Configuration Reference
The top-level entity in routerconfig.xml is <swiftlet name="sys$jms">.
<swiftlet name="sys$jms"> Properties
These properties are attributes of the <swiftlet name="sys$jms"> entity.
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
allow-same-clientid |
Boolean | false |
No | No | Allows multiple connection with the same JMS Client Id if set to true |
collect-interval |
Long | 10000 |
No | No | Collect Interval Messages/Sec |
max-connections |
Integer | -1 |
No | No | Maximum JMS Connections |
consumer-cache-low-water-mark |
Integer | 100 |
No | No | Consumer caches are refilled when reaching this mark (min: 0) |
crfactory-class |
String | com.swiftmq.auth.ChallengeResponseFactoryImpl |
No | Yes | Challenge/Response Factory Class |
<swiftlet name="sys$jms" allow-same-clientid="false" collect-interval="10000" max-connections="-1" consumer-cache-low-water-mark="100" crfactory-class="com.swiftmq.auth.ChallengeResponseFactoryImpl"/>
<intravm-connection-factories> in <swiftlet name="sys$jms">
IntraVM Connection Factories
Each <intravm-connection-factory> entry is identified by its name attribute (the IntraVM Connection Factory).
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
smqp-producer-reply-interval |
Integer | 20 |
Yes | No | Number of SMQP Requests after which a SMQP Reply is required (min: 1) |
smqp-consumer-cache-size |
Integer | 500 |
Yes | No | Cache Size per Consumer (Messages) (min: 1) |
smqp-consumer-cache-size-kb |
Integer | 2048 |
Yes | No | Cache Size per Consumer (KB) |
jms-client-id |
String | — | No | No | JMS Client Id for durable Subscribers |
jms-default-delivery-mode |
String | persistent |
Yes | No | JMS Default Delivery Mode (choices: persistent, non_persistent) |
jms-default-message-ttl |
Long | 0 |
Yes | No | JMS Default Message TTL (min: 0) |
jms-default-message-priority |
Integer | 4 |
Yes | No | JMS Default Message Priority (range: 0–9) |
jms-default-message-id-enabled |
Boolean | true |
No | No | JMS Default Message Id Enabled |
jms-default-message-timestamp-enabled |
Boolean | true |
No | No | JMS Default Message Timestamp Enabled |
thread-context-classloader-for-getobject |
Boolean | false |
No | No | Use the Thread Context Classloader for getObject() |
<swiftlet name="sys$jms">
<intravm-connection-factories>
<intravm-connection-factory name="..." smqp-producer-reply-interval="..." smqp-consumer-cache-size="..." smqp-consumer-cache-size-kb="..." jms-default-delivery-mode="..." jms-default-message-ttl="..." jms-default-message-priority="..."/>
</intravm-connection-factories>
</swiftlet>
<listeners> in <swiftlet name="sys$jms">
Listener Definitions
Each <listener> entry is identified by its name attribute (the Listener).
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
connectaddress |
String | — | No | No | Listener Connect IP Address for NAT |
connectport |
Integer | -1 |
No | No | Listener Connect Port for NAT |
bindaddress |
String | — | No | No | Listener Bind IP Address |
port |
Integer | — | Yes | No | Listener Port |
hostname2 |
String | — | No | No | Hostname of the 2nd HA Instance |
connectaddress2 |
String | — | No | No | Listener Connect IP Address for NAT of the 2nd HA Instance |
connectport2 |
Integer | -1 |
No | No | Listener Connect Port for NAT of the 2nd HA Instance |
bindaddress2 |
String | — | No | No | Listener Bind IP Address of the 2nd HA Instance |
port2 |
Integer | -1 |
No | No | Listener Port 2nd HA Instance of the 2nd HA Instance |
use-tcp-no-delay |
Boolean | true |
Yes | No | Use Tcp No Delay |
socketfactory-class |
String | com.swiftmq.net.PlainSocketFactory |
No | No | Listener Socketfactory Class |
keepalive-interval |
Long | 60000 |
No | No | Interval for sending Keep Alive Messages |
max-connections |
Integer | -1 |
No | No | Maximum JMS Connections for this Listener |
router-input-buffer-size |
Integer | 131072 |
No | No | Router Network Input Buffer Size (min: 1024) |
router-input-extend-size |
Integer | 65536 |
No | No | Router Network Input Extend Size (min: 1024) |
router-output-buffer-size |
Integer | 131072 |
No | No | Router Network Output Buffer Size (min: 1024) |
router-output-extend-size |
Integer | 65536 |
No | No | Router Network Output Extend Size (min: 1024) |
<swiftlet name="sys$jms">
<listeners>
<listener name="..." port="..." use-tcp-no-delay="..."/>
</listeners>
</swiftlet>
<host-access-list> in <listeners>
Host Access List
Each <host-access-entry> entry is identified by its name attribute (the Host Access Entry).
<swiftlet name="sys$jms">
<listeners>
<listener name="...">
<host-access-list>
<host-access-entry name="..."/>
</host-access-list>
</listener>
</listeners>
</swiftlet>
<connection-factories> in <listeners>
Connection Factories
Each <connection-factory> entry is identified by its name attribute (the Connection Factory).
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
reconnect-enabled |
Boolean | true |
No | No | Reconnect Enabled |
reconnect-max-retries |
Integer | 10 |
No | No | Maximum Retries for Reconnect |
reconnect-delay |
Long | 10000 |
No | No | Reconnect Delay in ms |
duplicate-message-detection |
Boolean | true |
No | No | Enables Duplicate Message Detection for Consumers |
duplicate-backlog-size |
Integer | 2000 |
No | No | Max. Number of Entries of JMS Message IDs in the Duplicate Backlog |
client-input-buffer-size |
Integer | 131072 |
No | No | Client Network Input Buffer Size (min: 1024) |
client-input-extend-size |
Integer | 65536 |
No | No | Client Network Input Extend Size (min: 1024) |
client-output-buffer-size |
Integer | 131072 |
No | No | Client Network Output Buffer Size (min: 1024) |
client-output-extend-size |
Integer | 131072 |
No | No | Client Network Output Extend Size (min: 1024) |
smqp-producer-reply-interval |
Integer | 20 |
Yes | No | Number of SMQP Requests after which a SMQP Reply is required (min: 1) |
smqp-consumer-cache-size |
Integer | 500 |
Yes | No | Cache Size per Consumer (Messages) (min: 1) |
smqp-consumer-cache-size-kb |
Integer | 2048 |
Yes | No | Cache Size per Consumer (KB) |
jms-client-id |
String | — | No | No | JMS Client Id for durable Subscribers |
jms-default-delivery-mode |
String | persistent |
Yes | No | JMS Default Delivery Mode (choices: persistent, non_persistent) |
jms-default-message-ttl |
Long | 0 |
Yes | No | JMS Default Message TTL (min: 0) |
jms-default-message-priority |
Integer | 4 |
Yes | No | JMS Default Message Priority (range: 0–9) |
jms-default-message-id-enabled |
Boolean | true |
No | No | JMS Default Message Id Enabled |
jms-default-message-timestamp-enabled |
Boolean | true |
No | No | JMS Default Message Timestamp Enabled |
thread-context-classloader-for-getobject |
Boolean | false |
No | No | Use the Thread Context Classloader for getObject() |
<swiftlet name="sys$jms">
<listeners>
<listener name="...">
<connection-factories>
<connection-factory name="..." smqp-producer-reply-interval="..." smqp-consumer-cache-size="..." smqp-consumer-cache-size-kb="..." jms-default-delivery-mode="..." jms-default-message-ttl="..." jms-default-message-priority="..."/>
</connection-factories>
</listener>
</listeners>
</swiftlet>