The JMS component allows messages to be sent to a JMS Queue or Topic; or messages to be consumed from a JMS Queue or Topic. 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.
![]() | Using ActiveMQ |
---|---|
If you are using Apache ActiveMQ you should prefer to use the ActiveMQ component as it has been particularly optimized for ActiveMQ. All the options and samples on this page applies as well for ActiveMQ component. |
jms:[topic:]destinationName?options
So for example to send to queue FOO.BAR you would use
jms:FOO.BAR
You can be completely specific if you wish via
jms:queue:FOO.BAR
If you want to send to a topic called Stocks.Prices then you would use
jms:topic:Stocks.Prices
As of 1.4.0 of FUSE Mediation Router you can use temporary queues using the following URL format
jms:temp:queue:foo
or temporary topics as
jms:temp:topic:bar
Where foo and bar, the text after the String jms:temp:queue: or jms:temp:topic:, are the names of the destinations. This enables multiple routes or processors or beans to refer to the same temporary destination. e.g. you can create 3 temporary destinations and use them in routes as inputs or outputs by referring to them by name.
![]() | If you are using ActiveMQ |
---|---|
Note that 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 JMS provider to avoid performance being lousy. So if you intent to use Apache ActiveMQ as your Message Broker - which is a good choice as ActiveMQ rocks :), then we recommend that you either
|
If you wish to use durable topic subscriptions, you need to specify both clientId and durableSubscriptionName. Note that 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 by default FUSE Mediation Router will ignore any headers which do not match this rule. So try name your headers as if they are valid Java identifiers. One added bonus of this is that you can then use your headers inside a JMS Selector - which uses SQL92 syntax which mandates Java identifier syntax for headers.
From FUSE Mediation Router 1.4 a simple strategy for mapping headers names is used by default. The strategy is to replace any dots in the headername with underscore, and vice-versa when the header name is restored from the JMS message that was sent over the wire. What does this means? No more loosing method names to invoke on a bean component, no more loosing the filename header for the File Component etc.
Current header name strategy used for accepting header names in FUSE Mediation Router:
replace all dots with underscores (e.g. org.apache.camel.MethodName
=> org_apache_camel_MethodName
)
test if the name is a valid java identifier using the JDK core classes
if test success then the header is added and sent over the wire, if not its dropped (logged at DEBUG level)
![]() | For Consuming Messages cacheLevelName settings are vital! |
---|---|
If you are using Spring before 2.5.1 and FUSE Mediation Router before 1.3.0 then you might want to set the cacheLevelName to be CACHE_CONSUMER for maximum performance. Due to a bug in earlier Spring versions causing a lack of transactional integrity, previous versions of FUSE Mediation Router and FUSE Mediation Router versions from 1.3.0 onwwards when used with earlier Spring versions than 2.5.1 will default to use CACHE_CONNECTION. See the JIRAs CAMEL-163 and CAMEL-294. Also if you are using XA or running in a J2EE container then you may want to set the cacheLevelName to be CACHE_NONE as we have seen using JBoss with TibCo EMS and JTA/XA you must disable caching. Another end user reports issue with using WebSphere MQ 6.0.2.5, FUSE Mediation Router 1.6.0 and Spring 2.5.6. Not running XA or inside a J2EE Container, but the cacheLevelName=CACHE_NONE seems to have solved the problem with WebSphere MQ. See also more about JmsTemplate gotchas. |
You can configure lots of different properties on the JMS endpoint which map to properties on the JMSConfiguration POJO. Notice: Many of these properties maps to properties on Spring JMS that FUSE Mediation Router uses for sending and receiving messages. So you can get more information about these properties by consulting the Spring documentation.
Option | Default Value | Description |
---|---|---|
acceptMessagesWhileStopping | false | Should the consumer accept messages while it is stopping |
acknowledgementModeName | "AUTO_ACKNOWLEDGE" | The JMS acknowledgement name which is one of: TRANSACTED, CLIENT_ACKNOWLEDGE, AUTO_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE |
acknowledgementMode | -1 | The JMS acknowledgement mode defined as an Integer. Allows to set vendor-specific extensions to the acknowledgment mode. For the regular modes prefer to use the acknowledgementModeName instead. |
alwaysCopyMessage | false | If true then FUSE Mediation Router will always make a JMS message copy of the message when it's passed to the producer for sending. Copying the message is needed in some situations such as when a replyToDestinationSelectorName is set (FUSE Mediation Router will by the way set the alwaysCopyMessage to true if a replyToDestinationSelectorName is set) |
autoStartup | true | Should the consumer container auto-startup |
cacheLevelName | "CACHE_CONSUMER" | Sets the cache level by name for the underlying JMS resources. Possible values are:
CACHE_AUTO, CACHE_CONNECTION, CACHE_CONSUMER, CACHE_NONE and
CACHE_SESSION . See the Spring documentation. And see the warning above. |
cacheLevel | -1 | Sets the cache level by id for the underlying JMS resources |
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. Its typically only required for durable topic subscriptions. You may prefer to use Virtual Topics instead |
consumerType | Default | The consumer type to use, either: Simple , Default
or ServerSessionPool . The consumer type determines which Spring JMS
listener should be used. Default will use
org.springframework.jms.listener.DefaultMessageListenerContainer .
Simple will use
org.springframework.jms.listener.SimpleMessageListenerContainer and
ServerSessionPool will use
org.springframework.jms.listener.serversession.ServerSessionMessageListenerContainer .
If option useVersion102=true then FUSE Mediation Router will of course
use the JMS 1.0.2 Spring classes instead. ServerSessionPool is
@deprecated and will be removed in FUSE Mediation
Router 2.0. |
concurrentConsumers | 1 | Specifies the default number of concurrent consumers |
connectionFactory | null | The default JMS connection factory to use for the listenerConnectionFactory and templateConnectionFactory if neither are specified |
deliveryPersistent | true | Is persistent delivery used by default? |
destination | null | (2.0 onwards) specifies the JMS Destination object to use on this endpoint |
destinationName | null | (2.0 onwards) specifies the JMS destination name to use on this endpoint |
disableReplyTo | false | Do you want to ignore the JMSReplyTo header and so treat messages as InOnly by default and not send a reply back? |
durableSubscriptionName | null | The durable subscriber name for specifying durable topic subscriptions |
eagerLoadingOfProperties | false | Enables eager loading of JMS properties as soon as a message is received which generally is inefficient as the JMS properties may not be required but sometimes can catch early any issues with the underlying JMS provider and the use of JMS properties. Can be used for testing purpose to ensure JMS properties can be understood and handled correctly. |
exceptionListener | null | The JMS Exception Listener used to be notified of any underlying JMS exceptions |
explicitQosEnabled | false | Set if the deliveryMode, priority or timeToLive should be used when sending messages |
exposeListenerSession | true | Set if the listener session should be exposed when consuming messages |
idleTaskExecutionLimit | 1 | Specify the limit for idle executions of a receive task, not having received any message within its execution. If this limit is reached, the task will shut down and leave receiving to other executing tasks (in case of dynamic scheduling; see the "maxConcurrentConsumers" setting). |
jmsMessageType | null |
FUSE Mediation Router 2.0: Allows you to force to use a
specific javax.jms.Message implementation for sending a jms message. Possible values:
Bytes, Map, Object, Stream, Text . By default FUSE Mediation Router
will determine from the IN body type which Jms message type to use. This option allows you
to choose it. |
jmsOperations | null | Allow to use your own implementation of the
org.springframework.jms.core.JmsOperations interface. FUSE Mediation
Router uses JmsTemplate as default. Can be used for testing purpose, but not used much as
stated in the spring API docs. |
jmsKeyFormatStrategy | default |
FUSE Mediation Router 2.0: Pluggable strategy for
encoding and decoding JMS keys so they can be compliant with the JMS spec. FUSE Mediation
Router provides two implementations out of the box: default and
passthrough . Default will safely marshal dots and hyphens (. and -).
Passthrough lets the key as is. Can be used for JMS brokers which do not care about JMS
header keys containing illegal characters. You can provide you own implementation of the
org.apache.camel.component.jms.JmsKeyFormatStrategy and refer to it
using the # notation. |
lazyCreateTransactionManager | true | (new added in FUSE Mediation Router 2.0)If it is true , FUSE Mediation Router will create a JmsTransactionManager if there is no transactionManager injected when the transacted is true |
listenerConnectionFactory | null | The JMS connection factory used for consuming messages |
maxConcurrentConsumers | 1 | Specifies the maximum number of concurrent consumers |
maxMessagesPerTask | 1 | The number of messages per task |
messageConverter | null | The Spring Message Converter |
messageIdEnabled | true | When sending, should message IDs be added |
messageTimestampEnabled | true | Should timestamps be enabled by default on sending messages |
password | null | The password which is set for the connector factory |
priority | -1 | Values of > 1 specify the message priority when sending, if the explicitQosEnabled property is specified (with 0 as the lowest priority and 9 as the highest) |
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 |
pubSubNoLocal | false | Set whether to inhibit the delivery of messages published by its own connection |
selector | null | Sets the JMS Selector which is an SQL 92 predicate used to apply to messages to filter them at the message broker. You may have to encode special characters such as = as %3D |
receiveTimeout | none | The timeout when receiving messages |
recoveryInterval | none | The recovery interval |
replyTo | null | Provides an explicit reply to destination which overrides any incoming value of
Message.getJMSReplyTo()
|
replyToTempDestinationAffinity | endpoint | defines the component created temporary replyTo destination sharing strategy. Possible
values are: component , endpoint or
producer . component = a single temp
queue is shared among all producers for a given component instance. endpoint = a single temp queue is shared among all producers for a given
endpoint instance. producer = a single temp queue is
created per producer. |
replyToDestinationSelectorName | null | Sets the JMS Selector using the fixed name to be used so you can filter out your own replies from the others, when using a shared queue (i.e. if you are not using a temporary reply queue). |
replyToDeliveryPersistent | true | Is persistent delivery used by default for reply? |
requestTimeout | 20000 | The timeout when sending messages |
serverSessionFactory | null | @deprecated - will be removed in FUSE Mediation Router 2.0. The JMS ServerSessionFactory if you wish to use ServerSessionFactory for consumption |
subscriptionDurable | false | Enabled by default if you specify a durableSubscriberName and a clientId |
taskExecutor | null | Allows you to specify a custom task executor for consuming messages |
templateConnectionFactory | null | The JMS connection factory used for sending messages |
timeToLive | null | Is a time to live specified when sending messages |
transacted | false | If transacted mode will be used for sending/receiving messages using the InOnly Exchange Pattern. See section Enabling Transacted Consumption for more details. |
transactedInOut | false | If transacted mode will be used when sending/receiving messages using the InOut Exchange Pattern. See section Enabling Transacted Consumption for more details. |
transactionManager | null | The Spring transaction manager to use |
transactionName | null | The name of the transaction to use |
transactionTimeout | null | The timeout value of the transaction if using transacted mode |
transferException | false |
FUSE Mediation Router 2.0: If enabled and you are using
Request Reply messaging (InOut) and an Exchange failed on the consumer side then the caused Exception will be send
back as response as a javax.jms.ObjectMessage . If the client is FUSE
Mediation Router then that returned Exception will be rethrown. This allows you to use
FUSE Mediation Router JMS as a bridge in your routing,
e.g. using persistent queues to enable robust routing. Notice that if you also have
transferExchange enabled then this option takes
precedence. The exceptions caught is required to be serializable. The original caused
Exception on the consumer side can be wrapped in an outer exception such as
org.apache.camel.RuntimeCamelException when returned to the producer.
|
transferExchange | false | FUSE Mediation Router 2.0: You can transfer the exchange over the wire instead of just the body and headers. The following fields is transferred: in body, out body, fault body, in headers, out headers, fault headers, exchange properties, exchange exception. This requires that the objects are Serializable. FUSE Mediation Router will exclude any non serializable objects and log it at WARN level. |
username | null | The username which is set for the connector factory |
useMessageIDAsCorrelationID | false | Should JMSMessageID be used as JMSCorrelationID
for InOut messages. FUSE Mediation Router will by default
use a GUID |
useVersion102 | false | Should the old JMS API be used |
FUSE Mediation Router will automatically map messages between
javax.jms.Message
and org.apache.camel.Message
.
When sending a JMS message FUSE Mediation Router will convert the body to the following JMS message:
Body Type | JMS Message | Comment |
---|---|---|
String |
javax.jms.TextMessage
|
|
org.w3c.dom.Node |
javax.jms.TextMessage
|
The DOM will be converted to String |
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
|
When receiving a JMS message FUSE Mediation Router will convert the JMS message to the following body type:
JMS Message | Body Type | Comment |
---|---|---|
javax.jms.TextMessage
|
String | |
javax.jms.BytesMessage
|
byte[] | |
javax.jms.MapMessage
|
Map<String, Object> | |
javax.jms.ObjectMessage
|
Object |
Available as of FUSE Mediation Router 2.0
You can use the option jmsMessageType on the endpoint to
force using a specific message type for all messages. In the route below we will 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 provide a per. message type as a header with the key
CamelJmsMessageType
.
from("file://inbox/order").setHeader("CamelJmsMessageType", JmsMessageType.Text).to("jms:queue:order");
The possible values is defined in an 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 keys:
Keys stating with JMS or JMSX is reserved. All user keys will be dropped.
exchange.in.headers
keys must be literals and all be valid Java
identifiers. (do not use dots in the key name)
In FUSE Mediation Router 1.4 onwards FUSE Mediation Router will automatically replace all dots with underscore for key names. And vice-versa when FUSE Mediation Router consumes JMS messages.
In FUSE Mediation Router 2.0 onwards FUSE Mediation Router will also replace all
hyphens with the special token: \_HYPHEN\_
. And vice-versa when FUSE
Mediation Router consumes JMS messages.
See also option jmsKeyFormatStrategy
introduced in FUSE Mediation Router 2.0.
For the exchange.in.header
the following rules apply for the values:
The values must be primitives or their counter objects (such as Integer, Long,
Character). String, CharSequence, Date, BigDecimal or BigInteger is all converted to their
toString()
representation. All other types is dropped.
FUSE Mediation Router will log with category
org.apache.camel.component.jms.JmsBinding
at DEBUG level if it drops a given header value. 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}
FUSE Mediation Router will add 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 |
FUSE Mediation Router will add 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 |
http://java.sun.com/javaee/5/docs/api/javax/jms/Message.html] for further details. |
You can configure your JMS provider inside the Spring XML as follows...
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> </camelContext> <bean id="activemq" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory"> <bean class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="vm://localhost?broker.persistent=false"/> </bean> </property> </bean>
Basically you can configure as many JMS component instances as you wish and give them a unique name via the id attribute. The above example configures an 'activemq' component. You could do the same to configure MQSeries, TibCo, BEA, Sonic etc.
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 as activemq:\queue:\destinationName. So you could use the same approach for working with 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 want to lookup in JNDI to find your 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. e.g.
<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"/>
A common requirement with JMS is to consume messages concurrently in many threads to achieve high throughput. As shown above you use the concurrentConsumers property above.
from("jms:SomeQueue?concurrentConsumers=20"). bean(MyClass.class);
You can configure the properties on the JmsComponent if you wish or on specific endpoints via the URI or by configuring the JmsEndpoint directly.
A common requirement is to consume from a queue in a transaction then process the message using the route. To do this just ensure you set the following properties on the component/endpoint
transacted = true
transactionManager = a Transsaction Manager - typically the JmsTransactionManager
See also the Transactional Client EIP pattern for further details.
![]() | Transaction and [Request Reply] over JMS |
---|---|
Note that when using Request Reply over JMS you cannot use a single transaction; as 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. So with request/response you must commit a transaction after sending the first request and then use a separate transaction for receiving the response. Its for this reason that the transacted property only applies to InOnly message Exchange Pattern. If you still want to use transacted for InOut then you must use transactedInOut=true. To recap: if you have |
Avaiable as of FUSE Mediation Router 2.0
When using FUSE Mediation Router as a JMS listener it will place a property on the
Exchange with the ReplyTo javax.jms.Destination
object in the key
ReplyTo
. You can obtain this Destination as shown here:
Destination replyDestination = exchange.getProperty(JmsConstants.JMS_REPLY_DESTINATION, Destination.class);
And then later use it to send a reply using regular or FUSE Mediation Router JMS.
// 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 it is to provide the replyDestination object in the same Exchange property when sending. Then FUSE Mediation Router will pickup this property and use it for the real destination. This requires however that you send it to some dummy destination. Okay here goes:
// 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.setProperty(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 FUSE Mediation Router
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 this 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 pattern so the route can be context based, such as filtering 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");
FUSE Mediation Router also has annotations so you can use POJO Consuming and POJO Producing.
The sample above are using the Java DSL. FUSE Mediation Router also supports using 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 is used a lot in other samples for other components and EIP patterns as well in this FUSE Mediation Router documentation. So feel free to browse the documentation. If you have good time then check out the this tutorial that uses JMS but focuses on how well Spring Remoting and FUSE Mediation Router works together Tutorial-JmsRemoting.
Available as of FUSE Mediation Router 2.0 Normally when
using JMS as transport in only transfers the body and
headers as payload. If you want to use JMS with 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 therefore use the
option transferExchange on the JMS dead letter queue to
instruct FUSE Mediation Router 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 grap the caused exception using a 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 a custom body as you can set as you like. We use Message Translator EIP to do a transformation on the failed exchange before its moved to the JMS dead letter queue. The demo below illustrates this:
// 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. Eg you can invoke a method on a Bean, use a custom processor or what else.
Transactional Client
Bean Integration
Tutorial-JmsRemoting