JMS Swiftlet
Overview
The JMS Swiftlet implements the core JMS (Java Message Service) protocol support for SwiftMQ routers, providing all functionality necessary for JMS client connectivity, messaging, and resource management. It manages inbound and outbound JMS connections, sessions, producers, consumers, temporary queues, durable subscriptions, and enforces resource limits and authentication. The Swiftlet also exposes detailed runtime usage statistics and supports advanced features such as message selectors, duplicate detection, and failover/reconnect.
Features
JMS Connection Management
The JMS Swiftlet manages all incoming JMS client connections, both over TCP and intra-VM (intravm). Each connection is tracked and limited according to global and per-listener maximums. The Swiftlet enforces unique JMS client IDs by default, but can be configured to allow duplicates. It handles authentication using a pluggable challenge/response mechanism and maintains runtime statistics for each connection, including messages sent/received per second and totals. Connections are monitored for activity, and keepalive intervals are enforced to detect and close stale sessions.
Connection Factories and Listeners
Listeners define network endpoints (ports, addresses) for JMS clients to connect. Each listener can have multiple connection factories, each with its own set of properties (e.g., reconnect behavior, buffer sizes, duplicate detection). Connection factories are registered in JNDI for client lookup. Intra-VM connection factories allow for high-performance, in-process JMS connections.
Host Access Control
Each listener can restrict inbound connections based on a host access list, using SQL-LIKE predicates (with % as a wildcard) to match allowed client addresses.
Authentication and Challenge/Response
Authentication is performed using a configurable challenge/response factory class. The default is com.swiftmq.auth.ChallengeResponseFactoryImpl, but this can be replaced to implement custom authentication schemes.
Configuration Example:
<swiftlet name="sys$jms" allow-same-clientid="true" max-connections="100" crfactory-class="com.example.CustomCRFactory">
<listeners>
<listener name="tcp-listener" port="4001">
<host-access-list>
<host-access-entry name="192.168.%"/>
</host-access-list>
<connection-factories>
<connection-factory name="cf1" reconnect-enabled="false" duplicate-message-detection="false"/>
</connection-factories>
</listener>
</listeners>
</swiftlet>
JMS Session, Producer, and Consumer Lifecycle
For each active JMS connection, the Swiftlet manages multiple JMS sessions, which may be transacted or non-transacted and support all standard JMS acknowledge modes. Each session can create producers (senders/publishers) and consumers (receivers/subscribers), with resource limits enforced per connection. The Swiftlet supports both queue and topic semantics, including temporary destinations and durable subscriptions. Message delivery is optimized with consumer-side caching and bulk delivery, and message selectors are fully supported for filtering.
Temporary Queues and Topics
Temporary queues are created per connection and are automatically deleted when the connection closes. Their names follow the pattern tmp$
Durable Subscriptions
Durable topic subscriptions are mapped to internal queues named
Message Selectors
Consumers and browsers can specify message selectors using standard JMS SQL-92 syntax. Selectors are compiled and validated at creation time, and only matching messages are delivered.
Configuration Example:
<swiftlet name="sys$jms">
<listeners>
<listener name="tcp-listener" port="4001">
<connection-factories>
<connection-factory name="cf1" smqp-consumer-cache-size="1000" smqp-consumer-cache-size-kb="4096"/>
</connection-factories>
</listener>
</listeners>
</swiftlet>
Resource Limits and Usage Statistics
The Swiftlet enforces resource limits for connections, sessions, producers, and consumers, both globally and per-listener. These limits prevent resource exhaustion and can be tuned for different deployment scenarios. The Swiftlet also collects and exposes detailed runtime statistics, such as messages per second and total messages sent/received per connection. These statistics are updated at a configurable interval and can be viewed via management tools.
Consumer Cache Low Water Mark
Each consumer maintains a message cache, which is refilled when the number of cached messages drops below the configured low water mark. This ensures efficient bulk delivery and minimizes latency.
Configuration Example:
<swiftlet name="sys$jms" consumer-cache-low-water-mark="50" collect-interval="5000"/>
Duplicate Message Detection and Reconnect
To ensure reliable message delivery, the JMS Swiftlet supports duplicate message detection for consumers. When enabled, a backlog of recent JMS message IDs is maintained to filter out duplicates, which is especially important in failover or reconnect scenarios. Connection factories can be configured to enable or disable duplicate detection, set the backlog size, and control reconnect behavior (number of retries, delay between attempts).
Configuration Example:
<swiftlet name="sys$jms">
<listeners>
<listener name="tcp-listener" port="4001">
<connection-factories>
<connection-factory name="cf1" duplicate-message-detection="true" duplicate-backlog-size="5000" reconnect-enabled="true" reconnect-max-retries="20" reconnect-delay="5000"/>
</connection-factories>
</listener>
</listeners>
</swiftlet>
Internal Queue Naming
tmp$<sequence>-<startuptime>— Temporary queues created per JMS connection; used for temporary destinations and automatically deleted when the connection closes.<clientId>$<durableName>— Internal queue for durable topic subscriptions, storing messages for offline durable subscribers.
Configuration Guide
Restricting JMS Connections to Specific Hosts
Use this scenario to allow only clients from certain IP address ranges to connect to a JMS listener, improving security and compliance.
- Define a listener with the desired port.
- Add host access entries using SQL-LIKE predicates (use % as wildcard) to match allowed client addresses.
<swiftlet name="sys$jms">
<listeners>
<listener name="secure-listener" port="4002">
<host-access-list>
<host-access-entry name="10.0.%.%"/>
<host-access-entry name="192.168.1.%"/>
</host-access-list>
<connection-factories>
<connection-factory name="cf-secure"/>
</connection-factories>
</listener>
</listeners>
</swiftlet>
Configuring a High-Performance IntraVM Connection Factory
Use this scenario to enable JMS clients running in the same JVM as the router to connect with minimal overhead, bypassing the network stack.
- Add an intraVM connection factory with custom cache sizes and delivery mode as needed.
<swiftlet name="sys$jms">
<intravm-connection-factories>
<intravm-connection-factory name="ivm-cf" smqp-consumer-cache-size="2000" smqp-consumer-cache-size-kb="8192" jms-default-delivery-mode="non_persistent"/>
</intravm-connection-factories>
</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>