JMS — allows message to be sent to or consumed from JMS destinations
The JMS component allows messages to be sent to (or consumed from) a JMS destination. The
implementation of the JMS Component uses Spring's JMS support for declarative
transactions, using Spring's JmsTemplate
for sending and a
MessageListenerContainer
for consuming.
![]() | Note |
---|---|
If you are using Red Hat JBoss A-MQ, use the ActiveMQ endpoint; it has been optimized for Red Hat JBoss A-MQ. All of the options and samples on this page are also valid for the ActiveMQ component. |
![]() | Note |
---|---|
If using transactions with JMS, see section Transactions and Cache Levels as it can impact performance. |
![]() | Note |
---|---|
Be sure to read the section Request-reply over JMS for important notes about request/reply, as Camel offers a number of options to configure for performance, and clustered environments. |
The URI format for a JMS endpoint is:
jms:[queue:|topic:]destinationName[?options]
Where destinationName
is a JMS queue or topic name. By default,
destinationName
is interpreted as a queue name. For example, to
connect to the queue, FOO.BAR
use:
jms:FOO.BAR
You can include the optional queue:
prefix, if you prefer:
jms:queue:FOO.BAR
To connect to a topic, you must include the
topic:
prefix. For example, to connect to the topic,
Stocks.Prices
, use:
jms:topic:Stocks.Prices
You append query options to the URI using the following format,
?option=value&option=value&...
Maven users will need to add the following dependency to their
pom.xml
for this component:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jms</artifactId> <version>x.x.x</version> <!-- use the same version as your Camel core version --> </dependency>
The JMS component reuses Spring 2's JmsTemplate
for sending
messages. This is not ideal for use in a non-J2EE container and typically requires some
caching in the JMS provider to avoid poor
performance.
If you intend to use Apache ActiveMQ as your Message Broker - which is a good choice as ActiveMQ rocks :-) , then we recommend that you either:
Use the ActiveMQ component, which is already optimized to use ActiveMQ efficiently
Use the PoolingConnectionFactory
in ActiveMQ.
If you are consuming messages and
using transactions (transacted=true
) then the default settings for
cache level can impact performance. If you are using XA transactions then you cannot
cache as it can cause the XA transaction to not work properly.
If you are not using XA, then you should consider
caching as it speeds up performance, such as setting
cacheLevelName=CACHE_CONSUMER
.
Through Camel 2.7.x, the default setting for cacheLevelName
is
CACHE_CONSUMER
. You will need to explicitly set
cacheLevelName=CACHE_NONE
. In Camel 2.8 onwards, the default
setting for cacheLevelName
is CACHE_AUTO
. This
default auto detects the mode and sets the cache level accordingly to:
CACHE_CONSUMER = if transacted=false
CACHE_NONE = if transacted=true
So you can say the default setting is conservative. Consider using
cacheLevelName=CACHE_CONSUMER
if you are using non-XA
transactions.
If you wish to use durable topic subscriptions, you need to specify both clientId and durableSubscriptionName. The value of the clientId
must be unique and can only be used by a single JMS connection instance in your entire
network. You may prefer to use Virtual Topics
instead to avoid this limitation. More background on durable messaging here.
When using message headers, the JMS specification states that header names must be valid Java identifiers. So try to name your headers to be valid Java identifiers. One benefit of doing this is that you can then use your headers inside a JMS Selector (whose SQL92 syntax mandates Java identifier syntax for headers).
A simple strategy for mapping header names is used by default. The strategy is to replace any dots and hyphens in the header name as shown below and to reverse the replacement when the header name is restored from a JMS message sent over the wire. What does this mean? No more losing method names to invoke on a bean component, no more losing the filename header for the File Component, and so on.
The current header name strategy for accepting header names in Camel is as follows:
Dots are replaced by \_DOT\_
and the replacement is
reversed when Camel consume the message
Hyphen is replaced by \_HYPHEN\_
and the replacement is
reversed when Camel consumes the message
JMS Common Options and Table 34, “Other JMS options” list the options for a JMS endpoint, which map to properties on the JMSConfiguration POJO.
![]() | Note |
---|---|
Many of these properties map to properties on Spring JMS, which Apache Camel uses for sending and receiving messages. You can get more information about these properties by consulting the relevant Spring documentation. |
Option | Default | Description |
---|---|---|
clientId
|
null
|
Sets the JMS client ID to use. Note that this value, if specified, must be unique and can only be used by a single JMS connection instance. It is typically only required for durable topic subscriptions. You may prefer to use Virtual Topics instead. |
concurrentConsumers
|
1
|
Specifies the default number of concurrent consumers. From Camel 2.10.3 onwards this option can also be used
when doing request/reply over JMS. See also the
maxMessagesPerTask option to control dynamic scaling
up/down of threads. |
disableReplyTo
|
false
|
If true , a producer will behave like a InOnly exchange with
the exception that JMSReplyTo header is sent out and not be
suppressed like in the case of InOnly . Like
InOnly the producer will not wait for a reply. A consumer
with this flag will behave like InOnly . This feature can be
used to bridge InOut requests to another queue so that a
route on the other queue will send its response directly back to the original
JMSReplyTo . |
durableSubscriptionName
|
null
|
The durable subscriber name for specifying durable topic subscriptions. The
clientId option must be
configured as well. |
maxConcurrentConsumers
|
1
|
Specifies the maximum number of concurrent consumers. From Camel 2.10.3 onwards this option can also be used
when doing request/reply over JMS. See also the
maxMessagesPerTask option to control dynamic scaling
up/down of threads. |
maxMessagesPerTask
|
\-1
|
The number of messages per task. \-1 is unlimited. If you use a range for
concurrent consumers (eg min < max), then this option can be used to set a
value to eg 100 to control how fast the consumers will shrink
when less work is required. |
preserveMessageQos
|
false
|
Set to true , if you want to send message using the QoS
settings specified on the message, instead of the QoS settings on the JMS
endpoint. The following three headers are considered
JMSPriority , JMSDeliveryMode , and
JMSExpiration . You can provide all or only some of them.
If not provided, Camel will fall back to use the values from the endpoint
instead. So, when using this option, the headers override the values from the
endpoint. The explicitQosEnabled option, by contrast, will
only use options set on the endpoint, and not values from the message header.
|
replyTo
|
null
|
Provides an explicit ReplyTo destination, which overrides any incoming value of
Message.getJMSReplyTo() . If you do Request Reply over JMS then make sure to read the section Request-reply
over JMS further below for more details, and the
replyToType option as well. |
replyToType
|
null
|
Camel 2.9: Allows for explicitly specifying
which kind of strategy to use for replyTo queues when doing request/reply over
JMS. Possible values are: Temporary ,
Shared , or Exclusive . By default Camel
will use temporary queues. However if replyTo has been
configured, then Shared is used by default. This option
allows you to use exclusive queues instead of shared ones. See further below for
more details, and especially the notes about the implications if running in a
clustered environment, and the fact that Shared reply queues
has lower performance than its alternatives Temporary and
Exclusive . |
requestTimeout
|
20000
|
Producer only: The timeout for waiting for a reply when using the InOut Exchange Pattern (in milliseconds). The default is 20 seconds. See below in section About time to live for more details. See also the requestTimeoutCheckerInterval option. |
selector
|
null
|
Sets the JMS Selector, which is an SQL 92 predicate that is used to filter messages within the broker. You may have to encode special characters such as = as %3D Before Camel 2.3.0, we don't support this option in CamelConsumerTemplate |
timeToLive
|
null
|
When sending messages, specifies the time-to-live of the message (in milliseconds). See below in section About time to live for more details. |
transacted
|
false
|
Specifies whether to use transacted mode for sending/receiving messages using the InOnly Exchange Pattern. |
testConnectionOnStartup
|
false
|
Camel 2.1: Specifies whether to test the connection on startup. This ensures that when Camel starts that all the JMS consumers have a valid connection to the JMS broker. If a connection cannot be granted then Camel throws an exception on startup. This ensures that Camel is not started with failed connections. From Camel 2.8 onwards also the JMS producers is tested as well. |
Table 34. Other JMS options
Option | Default | Description |
---|---|---|
acceptMessages
WhileStopping
|
false
|
Specifies whether the consumer accept messages while it is stopping. You might consider enabling this option, if you start and stop JMS routes at runtime, while there are still messages enqued on the queue. If this option is |
acknowledgement
ModeName
|
| The JMS acknowledgement name, which is one of:
SESSION_TRANSACTED ,
CLIENT_ACKNOWLEDGE ,
AUTO_ACKNOWLEDGE , and
DUPS_OK_ACKNOWLEDGE
|
acknowledgementMode
|
\-1
| The JMS acknowledgement mode defined as an Integer. This option
enables you to set vendor-specific extensions in the acknowledgment
mode. For the regular modes, it is preferable to use the
acknowledgementModeName . |
allowNullBody
|
true
| Camel 2.9.3/2.10.1: Specifies
whether to allow sending messages with no body. If this option is
false and the message body is null, an
JMSException is thrown. |
alwaysCopyMessage
|
false
|
If Camel sets the |
asyncConsumer
|
false
|
Camel 2.9: Specifies whether the
If enabled, the If disabled (as default), the Exchange is fully processed before the
|
asyncStartListener
|
false
|
Camel 2.10: Specifies whether to
startup the For example, if a Setting this option to |
asyncStopListener
|
false
| Camel 2.10: Specifies whether to
stop the JmsConsumer message listener asynchronously
when stopping a route. |
autoStartup
|
true
| Specifies whether the consumer container should auto-startup. |
cacheLevelName
|
(Camel 2.8.0+)
(Camel 2.7.1-) |
Sets the cache level by name for the underlying JMS resources.
Possible values are: Camel 2.8 onwards: The default
setting is For details, see the Spring documentation and Transactions and Cache Levels. |
cacheLevel
| Sets the cache level by ID for the underlying JMS resources. See
cacheLevelName option for more details. | |
consumerType
|
Default
|
Specifies the consumer type to use, which can be one of:
The consumer type determines which Spring JMS listener to use.
When |
connectionFactory
|
null
| The default JMS connection factory to use for the
listener ConnectionFactory and
templateConnectionFactory , if neither is
specified. |
defaultTask
ExecutorType
| (see description) |
Camel 2.10.4: Specifies the default TaskExecutor type to use in the DefaultMessageListenerContainer, for both consumer endpoints and the ReplyTo consumer of producer endpoints. Possible values: If not set, defaults to the previous behaviour, which uses a cached thread pool for consumer endpoints and SimpleAsync for reply consumers. The use of |
deliveryPersistent
|
true
| Specifies whether persistent delivery is used by default. |
destination
|
null
| Specifies the JMS Destination object to use on this endpoint. |
destinationName
|
null
| Specifies the JMS destination name to use on this endpoint. |
destinationResolver
|
null
| A pluggable
org.springframework.jms.support.destination. DestinationResolver
that allows you to use your own resolver (for example, to lookup the
real destination in a JNDI registry). |
disableTimeToLive
|
false
|
Camel 2.8: Use this option to force disabling time to live. For example, when you do request/reply over JMS, Camel, by
default, uses the The problem is that the systems clocks on the sender and the
receiver must be synchronized. This is not always easy to achieve.
In that case, you can use |
eagerLoadingOf
Properties
|
false
| Enables eager loading of JMS properties as soon as a message is received, which is generally inefficient, because the JMS properties might not be required. But this feature can sometimes catch early any issues with the underlying JMS provider and the use of JMS properties. This feature can also be used for testing purposes, to ensure JMS properties can be understood and handled correctly. |
exceptionListener
|
null
| Specifies the JMS Exception Listener that is to be notified of any underlying JMS exceptions. |
errorHandler
|
null
|
Camel 2.8.2, 2.9: Specifies a
By default, these exceptions are logged at the WARN level when no
Camel 2.9.1 onwards: Using the
next two options, you can configure the logging level and whether to
log stack traces. This is easier to configure than coding a custom
|
errorHandlerLogging
Level
|
WARN
| Camel 2.9.1: Allows to configure the
default errorHandler logging level for logging
uncaught exceptions. |
errorHandlerLog
StackTrace
|
true
| Camel 2.9.1: Allows to control
whether stacktraces should be logged or not, by the default
errorHandler . |
explicitQosEnabled
|
false
|
Sets whether the The |
exposeListenerSession
|
true
| Specifies whether the listener session should be exposed when consuming messages. |
forceSendOriginal
Message
|
false
|
Camel 2.7: When using
Set this option to |
idleTaskExecution
Limit
|
1
|
Specifies the limit for idle executions of a receive task that has not received any message within its execution. When this limit is reached, the task shuts down and leaves
receiving to other executing tasks (in the case of dynamic
scheduling; see the |
idleConsumerLimit
|
1
| Camel 2.8.2, 2.9: Specifies the limit for the number of consumers that can be idle at any given time. |
includeSentJMS
MessageID
|
false
|
Camel 2.10.3: Only applicable when sending to JMS destination using InOnly (eg fire and forget). Enabling this option enriches the Camel Exchange with the actual JMSMessageID that was used by the JMS client when the message was sent to the JMS destination. |
includeAllJMSX
Properties
|
false
|
Camel 2.11.2/2.12: Specifies whether to include all JMSXxxx properties when mapping from JMS to Camel Message. Setting this to If using a custom |
jmsMessageType
|
null
| Allows you to force the use of a specific
javax.jms.Message implementation for sending JMS
messages. Possible values are: Bytes ,
Map , Object ,
Stream , Text . By default,
Camel would determine which JMS message type to use from the In body
type. This option allows you to specify it. |
jmsKeyFormatStrategy
|
default
|
Pluggable strategy for encoding and decoding JMS keys so they can be compliant with the JMS specification. Camel provides two implementations out-of-the-box:
You can provide your own implementation of the
|
jmsOperations
|
null
|
Allows you to use your implementation of the
Camel uses |
lazyCreateTransaction
Manager
|
true
| If true , Camel creates a
JmsTransactionManager if there is no
transactionManager injected when option
transacted=true . |
listenerConnection
Factory
|
null
| Specifies the JMS connection factory used for consuming messages. |
mapJmsMessage
|
true
|
Specifies whether Camel should auto map the received JMS message
to an appropiate payload type, such as mapping
See section Message mapping for more details. |
maximumBrowseSize
|
\-1
| Limits the number of messages fetched at most, when browsing endpoints using Browse or JMX API. |
messageConverter
|
null
| Allows you to use a custom Spring
org.springframework.jms.support.converter. MessageConverter
so you can be 100% in control of how to map to/from a
javax.jms.Message . |
messageIdEnabled
|
true
| When sending, specifies whether message IDs should be added. |
messageListener
ContainerFactoryRef
|
null
|
Camel 2.10.2: Registry ID of the
Setting this will automatically set
|
messageTimestamp
Enabled
|
true
| Specifies whether timestamps should be enabled by default on sending messages. |
password
|
null
| Specifies the password for the connector factory. |
priority
|
4
|
Specifies the message priority. Values greater than The |
pubSubNoLocal
|
false
| Specifies whether to inhibit the delivery of messages published by its own connection. |
receiveTimeout
| None | Specifies the timeout for receiving messages (in milliseconds). |
recoveryInterval
|
5000
| Specifies the interval between recovery attempts—when a connection is being refreshed, in ms. The default is 5000 ms. |
replyToCacheLevelName
|
|
Camel 2.9.1: Sets the cache level by name for the reply consumer when doing request/reply over JMS. This option applies only when using fixed reply queues (not temporary ones). Camel, by default, uses:
Some JMS brokers, such as IBM WebSphere, may require you to set
the |
replyToDestination
SelectorName
|
null
|
Sets the JMS Selector specifying the fixed name to use, so you can filter out your own replies when using a shared queue (not using a temporary reply queue). |
replyToDelivery
Persistent
|
true
| Specifies whether to use persistent delivery by default for replies. |
requestTimeout
CheckerInterval
|
1000
|
Camel 2.9.2: Specifies how often Camel should check for timed out Exchanges when doing request/reply over JMS. By default, Camel checks once per second. But if you must react faster when a timeout occurs, you can lower this interval to check more frequently. The timeout is determined by the option requestTimeout. |
subscriptionDurable
|
false
| @deprecated: Enabled by default, if
you specify a durableSubscriberName and a
clientId . |
taskExecutor
|
null
| Specifies a custom task executor for consuming messages. |
taskExecutorSpring2
|
null
| Camel 2.6: To use when using Spring 2.x with Camel. Allows you to specify a custom task executor for consuming messages. |
templateConnection
Factory
|
null
| The JMS connection factory used for sending messages. |
transactedInOut
|
false
|
@deprecated: Specifies whether to use transacted mode for sending messages using the InOut Exchange Pattern. Applies only to producer endpoints. See section Enabling Transacted Consumption for more details. |
transactionManager
|
null
| Specifies the Spring transaction manager to use. |
transactionName
|
| Specifies the name of the transaction to use. |
transactionTimeout
|
null
| The timeout value of the transaction (in seconds) when using transacted mode. |
transferException
|
false
|
When enabled and you are using Request
Reply messaging (InOut)
and an Exchange fails on the
consumer side, the resulting If the client is Camel, the returned Note that if you have also enabled transferExchange, this option takes precedence. The caught exception must be serializable. The original
|
transferExchange
|
false
|
Allows you to transfer the exchange over the wire, not just the body and headers. The following fields are transferred: The objects must be serializable. Camel excludes any
non-serializable object and logs it at You must enable this option on both the producer and consumer side, so Camel knows the payload is an Exchange, not a regular payload. |
username
|
null
| The username for the connector factory. |
useMessageIDAs
CorrelationID
|
false
| Specifies whether JMSMessageID should always be
used as JMSCorrelationID for InOut messages. |
useVersion102
|
false
| @deprecated (removed from Camel 2.5 onwards): Specifies whether the old JMS API should be used. |
Apache Camel automatically maps messages between javax.jms.Message
and org.apache.camel.Message
.
When sending a JMS message, Apache Camel converts the message body to the JMS message types shown in Table 35.
Table 35. Mapping from Apache Camel to JMS
Body Type | JMS Message |
---|---|
String
|
javax.jms.TextMessage
|
org.w3c.dom.Node
[a]
|
javax.jms.TextMessage
|
Map
|
javax.jms.MapMessage
|
java.io.Serializable
|
javax.jms.ObjectMessage
|
byte[]
|
javax.jms.BytesMessage
|
java.io.File
|
javax.jms.BytesMessage
|
java.io.Reader
|
javax.jms.BytesMessage
|
java.io.InputStream
|
javax.jms.BytesMessage
|
java.nio.ByteBuffer
|
javax.jms.BytesMessage
|
[a] The DOM will be converted to |
When receiving a JMS message, Apache Camel converts the JMS message to body type listed in Table 36, “Mapping from JMS to Apache Camel”.
Table 36. Mapping from JMS to Apache Camel
JMS Message | Body Type |
---|---|
javax.jms.TextMessage
|
String
|
javax.jms.BytesMessage
|
byte[]
|
javax.jms.MapMessage
|
Map<String, Object>
|
javax.jms.ObjectMessage
|
Object
|
You can use the mapJmsMessage
option to disable the auto-mapping
above. If disabled, Camel will not try to map the received JMS message, but instead uses
it directly as the payload. This allows you to avoid the overhead of mapping and let
Camel just pass through the JMS message. For instance, it even allows you to route
javax.jms.ObjectMessage
JMS messages with classes you do
not have on the classpath.
You can use the messageConverter
option to do the mapping yourself
in a Spring
org.springframework.jms.support.converter.MessageConverter
class.
For example, in the route below we use a custom message converter when sending a message to the JMS order queue:
from("file://inbox/order").to("jms:queue:order?messageConverter=#myMessageConverter");
You can also use a custom message converter when consuming from a JMS destination.
You can use the jmsMessageType option on the endpoint
URL to force a specific message type for all messages. In the route below, we poll files
from a folder and send them as javax.jms.TextMessage
as we have
forced the JMS producer endpoint to use text messages:
from("file://inbox/order").to("jms:queue:order?jmsMessageType=Text");
You can also specify the message type to use for each messabe by setting the header
with the key CamelJmsMessageType
. For example:
from("file://inbox/order").setHeader("CamelJmsMessageType", JmsMessageType.Text).to("jms:queue:order");
The possible values are defined in the enum
class,
org.apache.camel.jms.JmsMessageType
.
The exchange that is sent over the JMS wire must conform to the JMS Message spec.
For the exchange.in.header
the following rules apply for the header
keys:
Keys starting with JMS
or JMSX
are
reserved.
exchange.in.headers
keys must be literals and all be valid
Java identifiers (do not use dots in the key name).
Camel replaces dots & hyphens and the reverse when when consuming JMS
messages: .
is replaced by \_DOT\_
and the
reverse replacement when Camel consumes the message. \-
is
replaced by \_HYPHEN\_
and the reverse replacement when Camel
consumes the message.
See also the option jmsKeyFormatStrategy
, which allows use
of your own custom strategy for formatting keys.
For the exchange.in.header
, the following rules apply for the
header values:
The values must be primitives or their counter objects (such as
Integer
, Long
,
Character
). The types, String
,
CharSequence
, Date
,
BigDecimal
and BigInteger
are all
converted to their toString()
representation. All other types
are dropped.
Camel will log with category
org.apache.camel.component.jms.JmsBinding
at DEBUG level if it drops a given header value. For
example:
2008-07-09 06:43:04,046 [main ] DEBUG JmsBinding - Ignoring non primitive header: order of class: org.apache.camel.component.jms.issues.DummyOrder with value: DummyOrder{orderId=333, itemId=4444, quantity=2}
Camel adds the following properties to the Exchange
when it
receives a message:
Property | Type | Description |
---|---|---|
org.apache.camel.jms.replyDestination
|
javax.jms.Destination
|
The reply destination. |
Camel adds the following JMS properties to the In message headers when it receives a JMS message:
Header | Type | Description |
---|---|---|
JMSCorrelationID
|
String
|
The JMS correlation ID. |
JMSDeliveryMode
|
int
|
The JMS delivery mode. |
JMSDestination
|
javax.jms.Destination
|
The JMS destination. |
JMSExpiration
|
long
|
The JMS expiration. |
JMSMessageID
|
String
|
The JMS unique message ID. |
JMSPriority
|
int
|
The JMS priority (with 0 as the lowest priority and 9 as the highest). |
JMSRedelivered
|
boolean
|
Is the JMS message redelivered. |
JMSReplyTo
|
javax.jms.Destination
|
The JMS reply-to destination. |
JMSTimestamp
|
long
|
The JMS timestamp. |
JMSType
|
String
|
The JMS type. |
JMSXGroupID
|
String
|
The JMS group ID. |
The JMS component is complex and you have to pay close attention to how it works in some cases. So this is a short summary of some of the areas/pitfalls to look for.
When Camel sends a message using its JMSProducer
, it checks the
following conditions:
The message exchange pattern,
Whether a JMSReplyTo
was set in the endpoint or in the
message headers,
Whether any of the following options have been set on the JMS endpoint:
disableReplyTo
, preserveMessageQos
,
explicitQosEnabled
.
All this can be a tad complex to understand and configure to support your use case.
The JmsProducer
behaves as follows, depending on configuration:
Exchange Pattern | Other options | Description |
---|---|---|
InOut | \- | Camel will expect a reply, set a temporary JMSReplyTo , and
after sending the message, it will start to listen for the reply message on the
temporary queue. |
InOut | JMSReplyTo is set |
Camel will expect a reply and, after sending the message, it will start to
listen for the reply message on the specified JMSReplyTo
queue. |
InOnly | \- | Camel will send the message and not expect a reply. |
InOnly | JMSReplyTo is set |
By default, Camel discards the JMSReplyTo destination and
clears the JMSReplyTo header before sending the message.
Camel then sends the message and does not
expect a reply. Camel logs this in the log at WARN level
(changed to DEBUG level from Camel
2.6 onwards. You can use
preserveMessageQuo=true to instruct Camel to keep the
JMSReplyTo . In all situations the
JmsProducer does not
expect any reply and thus continue after sending the message. |
The JmsConsumer
behaves as follows, depending on configuration:
Exchange Pattern | Other options | Description |
---|---|---|
InOut | \- | Camel will send the reply back to the JMSReplyTo queue.
|
InOnly | \- | Camel will not send a reply back, as the pattern is InOnly. |
\- |
disableReplyTo=true
|
This option suppresses replies. |
So pay attention to the message exchange pattern set on your exchanges.
If you send a message to a JMS destination in the middle of your route you can specify
the exchange pattern to use, see more at Request
Reply. This is useful if you want to send an InOnly
message to a JMS topic:
from("activemq:queue:in") .to("bean:validateOrder") .to(ExchangePattern.InOnly, "activemq:topic:order") .to("bean:handleOrder");
If you need to send messages to a lot of different JMS destinations, it makes sense to reuse a JMS endpoint and specify the real destination in a message header. This allows Camel to reuse the same endpoint, but send to different destinations. This greatly reduces the number of endpoints created and economizes on memory and thread resources.
You can specify the destination in the following headers:
Header | Type | Description |
---|---|---|
CamelJmsDestination
|
javax.jms.Destination
|
A destination object. |
CamelJmsDestinationName
|
String
|
The destination name. |
For example, the following route shows how you can compute a destination at run time and use it to override the destination appearing in the JMS URL:
from("file://inbox") .to("bean:computeDestination") .to("activemq:queue:dummy");
The queue name, dummy
, is just a placeholder. It must be provided
as part of the JMS endpoint URL, but it will be ignored in this example.
In the computeDestination
bean, specify the real destination by
setting the CamelJmsDestinationName
header as follows:
public void setJmsHeader(Exchange exchange) { String id = .... exchange.getIn().setHeader("CamelJmsDestinationName", "order:" + id"); }
Then Camel will read this header and use it as the destination instead of the one
configured on the endpoint. So, in this example Camel sends the message to
activemq:queue:order:2
, assuming the id
value
was 2.
If both the CamelJmsDestination
and the
CamelJmsDestinationName
headers are set,
CamelJmsDestination
takes priority.
You can configure your JMS provider in Spring XML as follows:
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <jmxAgent id="agent" disabled="true"/> </camelContext> <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent"> <property name="connectionFactory"> <bean class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="vm://localhost?broker.persistent=false&roker.useJmx=false"/> </bean> </property> </bean>
Basically, you can configure as many JMS component instances as you wish and give them
a unique name using theid
attribute. The preceding example configures an activemq
component.
You could do the same to configure MQSeries, TibCo, BEA, Sonic and so on.
Once you have a named JMS component, you can then refer to endpoints within that
component using URIs. For example for the component name, activemq
,
you can then refer to destinations using the URI format,
activemq:[queue:|topic:]destinationName
. You can use the same
approach for all other JMS providers.
This works by the SpringCamelContext lazily fetching components from the spring context for the scheme name you use for Endpoint URIs and having the Component resolve the endpoint URIs.
If you are using a J2EE container, you might need to look up JNDI to find the JMS
ConnectionFactory
rather than use the usual
<bean>
mechanism in Spring. You can do this using Spring's
factory bean or the new Spring XML namespace. For example:
<bean id="weblogic" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory" ref="myConnectionFactory"/> </bean> <jee:jndi-lookup id="myConnectionFactory" jndi-name="jms/connectionFactory"/>
See The jee schema in the Spring reference documentation for more details about JNDI lookup.
A common requirement with JMS is to consume messages concurrently in multiple threads
in order to make an application more responsive. You can set the
concurrentConsumers
option to specify the number of threads
servicing the JMS endpoint, as follows:
from("jms:SomeQueue?concurrentConsumers=20"). bean(MyClass.class);
You can configure this option in one of the following ways:
On the JmsComponent
,
On the endpoint URI or,
By invoking setConcurrentConsumers()
directly on the
JmsEndpoint
.
Camel supports Request Reply over JMS. In essence
the MEP of the Exchange should be InOut
when you send a message to a
JMS queue.
Camel offers a number of options to configure request/reply over JMS that influence performance and clustered environments. The table below summaries the options.
Option | Performance | Cluster | Description |
---|---|---|---|
Temporary
|
Fast | Yes | A temporary queue is used as reply queue, and automatic created by Camel. To use
this do not specify a replyTo queue name. And
you can optionally configure replyToType=Temporary to make it
stand out that temporary queues are in use. |
Shared
|
Slow | Yes | A shared persistent queue is used as reply queue. The queue must be created
beforehand, although some brokers can create them on the fly such as Apache
ActiveMQ. To use this you must specify the replyTo queue name. And you can
optionally configure replyToType=Shared to make it stand out
that shared queues are in use. A shared queue can be used in a clustered
environment with multiple nodes running this Camel application at the same time.
All using the same shared reply queue. This is possible because JMS Message
selectors are used to correlate expected reply messages; this impacts
performance though. JMS Message selectors is slower, and therefore not as fast
as Temporary or Exclusive queues. See
further below how to tweak this for better performance. |
Exclusive
|
Fast | No | An exclusive persistent queue is used as reply queue. The queue must be created
beforehand, although some brokers can create them on the fly such as Apache
ActiveMQ. To use this you must specify the replyTo queue name. And you must configure
replyToType=Exclusive to instruct Camel to use exclusive
queues, as Shared is used by default, if a
replyTo queue name was configured. When using exclusive
reply queues, then JMS Message selectors are not in use, and therefore other applications must not use this
queue as well. An exclusive queue cannot be
used in a clustered environment with multiple nodes running this Camel
application at the same time; as we do not have control if the reply queue comes
back to the same node that sent the request message; that is why shared queues
use JMS Message selectors to make sure of this. Though if you configure each Exclusive reply queue with an
unique name per node, then you can run this in a clustered environment. As then
the reply message will be sent back to that queue for the given node, that
awaits the reply message. |
concurrentConsumers
|
Fast | Yes | Camel 2.10.3: Allows to process reply messages
concurrently using concurrent message listeners in use. You can specify a range
using the concurrentConsumers and
maxConcurrentConsumers options. Notice: That using Shared reply queues may
not work as well with concurrent listeners, so use this option with care. |
maxConcurrentConsumers
|
Fast | Yes | Camel 2.10.3: Allows to process reply messages
concurrently using concurrent message listeners in use. You can specify a range
using the concurrentConsumers and
maxConcurrentConsumers options. Notice: That using Shared reply queues may
not work as well with concurrent listeners, so use this option with care. |
The JmsProducer
detects the InOut
and provides a
JMSReplyTo
header with the reply destination to be used. By
default Camel uses a temporary queue, but you can use the replyTo
option on the endpoint to specify a fixed reply queue (see more below about fixed reply
queue).
Camel will automatic setup a consumer which listen on the reply queue, so you should
not do anything. This consumer is a Spring
DefaultMessageListenerContainer
which listen for replies. However
it's fixed to 1 concurrent consumer. That means replies will be processed in sequence as
there are only 1 thread to process the replies. If you want to process replies faster,
then we need to use concurrency. But not using the
concurrentConsumer
option. We should use the
threads
from the Camel DSL instead, as shown in the route
below:
from(xxx) .inOut().to("activemq:queue:foo") .threads(5) .to(yyy) .to(zzz);
In this route we instruct Camel to route replies asynchronously using a thread pool with 5 threads.
From Camel 2.10.3 onwards you can now configure the listener to use concurrent threads
using the concurrentConsumers
and
maxConcurrentConsumers
options. This allows you to easier
configure this in Camel as shown below:
from(xxx) .inOut().to("activemq:queue:foo?concurrentConsumers=5") .to(yyy) .to(zzz);
If you use a fixed reply queue when doing Request Reply over JMS as shown in the example below, then pay attention.
from(xxx) .inOut().to("activemq:queue:foo?replyTo=bar") .to(yyy)
In this example the fixed reply queue named "bar" is used. By default Camel assumes
the queue is shared when using fixed reply queues, and therefore it uses a
JMSSelector
to only pickup the expected reply messages (eg based
on the JMSCorrelationID
). See next section for exclusive fixed reply
queues. That means its not as fast as temporary queues. You can speedup how often Camel
will pull for reply messages using the receiveTimeout
option. By
default its 1000 millis. So to make it faster you can set it to 250 millis to pull 4
times per second as shown:
from(xxx) .inOut().to("activemq:queue:foo?replyTo=bar&receiveTimeout=250") .to(yyy)
Notice this will cause the Camel to send pull requests to the message broker more frequent, and thus require more network traffic. It is generally recommended to use temporary queues if possible.
Available as of Camel 2.9
In the previous example, Camel would anticipate the fixed reply queue named "bar" was
shared, and thus it uses a JMSSelector
to only consume reply messages
which it expects. However there is a drawback doing this as JMS selectos is slower. Also
the consumer on the reply queue is slower to update with new JMS selector ids. In fact
it only updates when the receiveTimeout
option times out, which by
default is 1 second. So in theory the reply messages could take up till about 1 sec to
be detected. On the other hand if the fixed reply queue is exclusive to the Camel reply
consumer, then we can avoid using the JMS selectors, and thus be more performant. In
fact as fast as using temporary queues. So in Camel 2.9
onwards we introduced the ReplyToType
option which you can configure
to Exclusive
to tell Camel that the reply queue is exclusive as shown
in the example below:
from(xxx) .inOut().to("activemq:queue:foo?replyTo=bar&replyToType=Exclusive") .to(yyy)
Mind that the queue must be exclusive to each and every endpoint. So if you have two routes, then they each need an unique reply queue as shown in the next example:
from(xxx) .inOut().to("activemq:queue:foo?replyTo=bar&replyToType=Exclusive") .to(yyy) from(aaa) .inOut().to("activemq:queue:order?replyTo=order.reply&replyToType=Exclusive") .to(bbb)
The same applies if you run in a clustered environment. Then each node in the cluster must use an unique reply queue name. As otherwise each node in the cluster may pickup messages which was intended as a reply on another node. For clustered environments its recommended to use shared reply queues instead.
When doing messaging between systems, its desirable that the systems have synchronized clocks. For example when sending a JMS message, then you can set a time to live value on the message. Then the receiver can inspect this value, and determine if the message is already expired, and thus drop the message instead of consume and process it. However this requires that both sender and receiver have synchronized clocks. If you are using ActiveMQ then you can use the timestamp plugin to synchronize clocks.
Read first above about synchronized clocks.
When you do request/reply (InOut) over JMS with
Camel then Camel uses a timeout on the sender side, which is default 20 seconds from the
requestTimeout
option. You can control this by setting a
higher/lower value. However the time to live value is still set on the JMS message being send. So that requires the clocks to
be synchronized between the systems. If they are not, then you may want to disable the
time to live value being set. This is now possible using the
disableTimeToLive
option from Camel
2.8 onwards. So if you set this option to
disableTimeToLive=true
, then Camel does not set any time to live value when sending JMS messages. But the request timeout is
still active. So for example if you do request/reply over JMS and have disabled time to live, then Camel will still use a timeout by
20 seconds (the requestTimeout
option). That option can of course
also be configured. So the two options requestTimeout
and
disableTimeToLive
gives you fine grained control when doing
request/reply.
When you do fire and forget (InOut) over JMS with
Camel then Camel by default does not set any time to
live value on the message. You can configure a value by using the
timeToLive
option. For example to indicate a 5 sec., you set
timeToLive=5000
. The option disableTimeToLive
can be used to force disabling the time to live, also for InOnly messaging. The
requestTimeout
option is not being used for InOnly
messaging.
A common requirement is to consume from a queue in a transaction and then process the message using the Camel route. To do this, just ensure that you set the following properties on the component/endpoint:
transacted
= true
transactionManager
= a Transsaction
Manager \- typically the JmsTransactionManager
See the Transactional Client EIP pattern for further details.
![]() | Important |
---|---|
When using Request Reply over JMS you cannot use a single transaction; JMS will not send any messages until a commit is performed, so the server side won't receive anything at all until the transaction commits. Therefore to use Request Reply you must commit a transaction after sending the request and then use a separate transaction for receiving the response. To address this issue the JMS component uses different properties to specify transaction use for oneway messaging and request reply messaging: The The If you want to use transactions for Request
Reply(InOut MEP), you must set
|
Available as of Camel 2.10
You can leverage the DMLC transacted session API using the following properties on component/endpoint:
transacted
= true
lazyCreateTransactionManager
= false
The benefit of doing so is that the cacheLevel setting will be honored when using local transactions without a configured TransactionManager. When a TransactionManager is configured, no caching happens at DMLC level and its necessary to rely on a pooled connection factory. For more details about this kind of setup see here and here.
When using Camel as a JMS listener, it sets an Exchange property with the value of the
ReplyTo javax.jms.Destination
object, having the key
ReplyTo
. You can obtain this Destination
as
follows:
Destination replyDestination = exchange.getIn().getHeader(JmsConstants.JMS_REPLY_DESTINATION, Destination.class);
And then later use it to send a reply using regular JMS or Camel.
// we need to pass in the JMS component, and in this sample we use ActiveMQ JmsEndpoint endpoint = JmsEndpoint.newInstance(replyDestination, activeMQComponent); // now we have the endpoint we can use regular Camel API to send a message to it template.sendBody(endpoint, "Here is the late reply.");
A different solution to sending a reply is to provide the
replyDestination
object in the same Exchange property when
sending. Camel will then pick up this property and use it for the real destination. The
endpoint URI must include a dummy destination, however. For example:
// we pretend to send it to some non existing dummy queue template.send("activemq:queue:dummy, new Processor() { public void process(Exchange exchange) throws Exception { // and here we override the destination with the ReplyTo destination object so the message is sent to there instead of dummy exchange.getIn().setHeader(JmsConstants.JMS_DESTINATION, replyDestination); exchange.getIn().setBody("Here is the late reply."); } }
In the sample below we send a Request Reply style
message Exchange (we use the
requestBody
method = InOut
) to the slow queue
for further processing in Camel and we wait for a return reply:
// send a in-out with a timeout for 5 sec Object out = template.requestBody("activemq:queue:slow?requestTimeout=5000", "Hello World");
JMS is used in many examples for other components as well. But we provide a few samples below to get started.
In the following sample we configure a route that receives JMS messages and routes the message to a POJO:
from("jms:queue:foo"). to("bean:myBusinessLogic");
You can of course use any of the EIP patterns so the route can be context based. For example, here's how to filter an order topic for the big spenders:
from("jms:topic:OrdersTopic"). filter().method("myBean", "isGoldCustomer"). to("jms:queue:BigSpendersQueue");
In the sample below we poll a file folder and send the file content to a JMS topic. As
we want the content of the file as a TextMessage
instead of a
BytesMessage
, we need to convert the body to a
String
:
from("file://orders"). convertBodyTo(String.class). to("jms:topic:OrdersTopic");
The preceding examples use the Java DSL. Camel also supports Spring XML DSL. Here is the big spender sample using Spring DSL:
<route> <from uri="jms:topic:OrdersTopic"/> <filter> <method bean="myBean" method="isGoldCustomer"/> <to uri="jms:queue:BigSpendersQueue"/> </filter> </route>
JMS appears in many of the examples for other components and EIP patterns, as well in this Camel documentation. So feel free to browse the documentation. If you have time, check out the this tutorial that uses JMS but focuses on how well Spring Remoting and Camel works together Tutorial-JmsRemoting.
Normally, when using JMS as the transport, it only
transfers the body and headers as the payload. If you want to use JMS
with a Dead
Letter Channel, using a JMS queue as the Dead Letter Queue, then normally the
caused Exception is not stored in the JMS message. You can, however, use the transferExchange option on the JMS dead letter queue to
instruct Camel to store the entire Exchange in the queue
as a javax.jms.ObjectMessage
that holds a
org.apache.camel.impl.DefaultExchangeHolder
. This allows you to
consume from the Dead Letter Queue and retrieve the caused exception from the Exchange
property with the key Exchange.EXCEPTION_CAUGHT
. The demo below
illustrates this:
// setup error handler to use JMS as queue and store the entire Exchange errorHandler(deadLetterChannel("jms:queue:dead?transferExchange=true"));
Then you can consume from the JMS queue and analyze the problem:
from("jms:queue:dead").to("bean:myErrorAnalyzer"); // and in our bean String body = exchange.getIn().getBody(); Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); // the cause message is String problem = cause.getMessage();
You can use JMS to store the cause error message or to store a custom body, which you can initialize yourself. The following example uses the Message Translator EIP to do a transformation on the failed exchange before it is moved to the JMS dead letter queue:
// we sent it to a seda dead queue first errorHandler(deadLetterChannel("seda:dead")); // and on the seda dead queue we can do the custom transformation before its sent to the JMS queue from("seda:dead").transform(exceptionMessage()).to("jms:queue:dead");
Here we only store the original cause error message in the transform. You can, however, use any Expression to send whatever you like. For example, you can invoke a method on a Bean or use a custom processor.
When sending to a JMS destination using camel-jms the producer will use the MEP to detect if its InOnly or InOut messaging. However there can be times where you want to send an InOnly message but keeping the JMSReplyTo header. To do so you have to instruct Camel to keep it, otherwise the JMSReplyTo header will be dropped.
For example to send an InOnly message to the foo queue, but with a JMSReplyTo with bar queue you can do as follows:
template.send("activemq:queue:foo?preserveMessageQos=true", new Processor() { public void process(Exchange exchange) throws Exception { exchange.getIn().setBody("World"); exchange.getIn().setHeader("JMSReplyTo", "bar"); } });
Notice we use preserveMessageQos=true
to instruct Camel to keep the
JMSReplyTo header.
Some JMS providers, like IBM's WebSphere MQ need options to be set on the JMS destination. For example, you may need to specify the targetClient option. Since targetClient is a WebSphere MQ option and not a Camel URI option, you need to set that on the JMS destination name like so:
... .setHeader("CamelJmsDestinationName", constant("queue:///MY_QUEUE?targetClient=1")) .to("wmq:queue:MY_QUEUE?useMessageIDAsCorrelationID=true");
Some versions of WMQ won't accept this option on the destination name and you will get an exception like:
com.ibm.msg.client.jms.DetailedJMSException: JMSCC0005: The specified value 'MY_QUEUE?targetClient=1' is not allowed for 'XMSC_DESTINATION_NAME'
A workaround is to use a custom DestinationResolver:
JmsComponent wmq = new JmsComponent(connectionFactory); wmq.setDestinationResolver(new DestinationResolver(){ public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain) throws JMSException { MQQueueSession wmqSession = (MQQueueSession) session; return wmqSession.createQueue("queue:///" + destinationName + "?targetClient=1"); } });