JMS Quickstart
Often you might want to configure a pair of connectors: one to send and one to receive messages to/from a destination. This guide explains how to do this using JMS.
For more complete examples of using connectors to consume and produce messages in general, see Asynchronous Request-Reply.
Step 1: Add connector-jms dependency
The dependency to add to your pom.xml is:
<dependency>
<groupId>com.iconsolutions.ipf.core.connector</groupId>
<artifactId>connector-jms</artifactId>
</dependency>
If importing the Icon BOM, or using the Icon BOM as a parent, there’s no need to supply a separate version.
Step 2: Configuration
Connector configuration - in general - is heavily config-driven.The configuration allows us to specify:
-
Queue/Topic names
-
JMS consumer/producer settings
-
Restart settings (on failure)
Here’s an example of a configuration block for a pair of sending and receiving connectors which we will wire into our
ConnectorTransport s, for a fictional bank’s booking system which features a request and response topic:
mybank.booking {
producer { (1)
queue = "mybank.booking.request" (2)
}
consumer { (3)
queue = "mybank.booking.response" (4)
}
}
If producing to an IBM MQ queue, the default behaviour is to produce a message with an MQRFH2 header. This can cause issues if the application which consumes the message is a non-JMS application. In such cases specifying queue:///$<queueName>?targetClient=1 will produce the message without the MQRFH2 header. So in the above example, the queue property would be "queue:///mybank.booking.request?targetClient=1" to produce messages without an MQRFH2 header.For more information see: www.ibm.com/docs/en/ibm-mq/9.3?topic=conversion-jms-message-types |
| 1 | This is known as the config root path and will be referenced in the code. It indicates where in the application’s configuration to look for this Send Connector Transport’s settings |
| 2 | The queue to send to |
| 3 | The config root path to the JMS consumer |
| 4 | The queue to receive from |
Step 2.1: Common Configuration
By default - the JMS configuration you specify here will fall back to the alpakka.jakarta-jms.consumer and
alpakka.jakarta-jms.producer settings.
What this means is that you can simply specify alpakka.jakarta-jms.consumer or alpakka.jakarta-jms.producer settings to globally
configure all JMS settings for all JMS consumers and producers. For example:
alpakka.jakarta-jms.consumer.acknowledge-mode = client
alpakka.jakarta-jms.producer.session-count = 10
If - for example - one specific JMS producer or consumer has different settings, it can be configured as such:
alpakka.jakarta-jms.producer.session-count = 10
mybank.booking.producer.session-count = 1
The above configuration means that all JMS producers - apart from the booking producer - will have 10 JMS Session instances, and the booking producer will only have one.
Step 3: Create Send Connector Transport
Here’s an example of how a SendConnectorTransport can be created for JMS:
var sendingTransport = JmsConnectorTransport.builder()
.withName("accounts-booking-send-transport") (1)
.withActorSystem(actorSystem)
.withConfigRootPath("mybank.booking.producer") (2)
.withConnectionFactory(connectionFactory) (3)
.build();
| 1 | Give the ConnectorTransport a meaningful name |
| 2 | Using the mybank.booking.producer configuration key defined in Step 2 |
| 3 | Provide a JMS ConnectionFactory here |
Step 4: Create Receive Connector Transport
Receive Connector Transport Configuration
Two JMS Receive Connector Transport types are available that each support different message acknowledgement requirements:
JmsReceiveConnectorTransport
When using this transport, no message acknowledgements are sent back to the broker, as messages are automatically considered acknowledged upon delivery.
JmsAckReceiveConnectorTransport
This transport uses CLIENT_ACKNOWLEDGEMENT mode, where the receiver explicitly acknowledges messages after they have been processed successfully.
It is important to note that acknowledgements in this mode are session-wide: acknowledging one message acknowledges all previously delivered messages in that session. Therefore, at-least-once delivery guarantees require max-pending-acks to be set to 0. With this configuration, increasing the message consumption throughput can be achieved by increasing the session-count property value.
Default JMS Receive Transport configuration
In addition to the common consumer configuration extended from Alpakka (covered in Step 2), the default JMS Receive Transport configuration applies the following overrides:
default-consumer = {
connection-retry {
max-retries = -1
}
# https://doc.akka.io/docs/alpakka/current/jms/consumer.html#configure-jms-consumers
# The sessionCount parameter controls the number of JMS sessions to run in parallel.
session-count = 5
# max-pending-acks - Maximum number of acknowledgements queued before they are sent to the broker.
# at-least-once message delivery guarantees can be achieved by setting max-pending-acks to 0.
max-pending-acks = 0
# health check settings for this consumer
health-check-settings = ${jms.health-check-settings}
}
Create Receive Connector Transport
Here’s how to create a ConnectorTransport for receiving messages over JMS:
var receivingTransport = JmsReceiveConnectorTransport.builder() (1)
.withName("accounts-booking-send-transport") (2)
.withActorSystem(actorSystem)
.withConfigRootPath("mybank.booking.consumer") (3)
.withConnectionFactory(connectionFactory) (4)
.build();
| 1 | You can use JmsReceiveConnectorTransport or JmsAckReceiveConnectorTransport builder here, depending on the required acknowledgement behaviour |
| 2 | Give the ConnectorTransport a meaningful name |
| 3 | Using the mybank.booking.consumer configuration key defined in Step 2 |
| 4 | Provide a JMS ConnectionFactory here |