Why does my camel route try to reply to the JMS consumer? - jms

I have an Apache Camel route configured in Spring which takes a message from a JMS (ActiveMQ) queue, transforms the message and uses the CXF component to send the results to a web service. This all works fine but I always get an exception thrown at the end of the route that the CXF response object isn't synchronizable, referring to the fact that it's trying to convert the exchange/message body back into a JMS message. But why?
Here's my camel context extract:-
<route>
<from uri="jms:queue:transactions" />
<process ref="convertToFormatForCXF" />
<to uri="cxf:bean:myService?defaultOperationName=process" />
<stop />
</route>
and here's a snippet from the logs:-
EndpointMessageListener WARN Execution of JMS message listener failed. Caused by: [org.apache.camel.RuntimeCamelException - java.lang.RuntimeException: net.sophis.soa.dataexchange.LogoutResponse]
org.apache.camel.RuntimeCamelException: java.lang.RuntimeException: net.sophis.soa.dataexchange.LogoutResponse
at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1363)
at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:124)
Even the doesn't prevent the stack trace. Now I've found out that if I add the disableReplyTo=true to the JMS consumer then the stacktrace doesn't show which is excellent.
I suppose I'm just trying to work out what was happening? Was the CXF response object going to be added to the 'transactions' JMS queue? My intention was for the flow to stop once the CXF producer had completed.
Can anyone help my understanding please? The Camel documentation wasn't much help on this.

Was the CXF response object going to be added to the 'transactions' JMS queue?
No. It would have been added to a temporary queue.
From http://camel.apache.org/jms.html#JMS-Request-replyoverJMS
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.

Related

Spring Integration - JMS to Kafka message transfer - End to End Transaction

I am consuming messages from JMS ActiveMQ using the following code:
<jms:message-driven-channel-adapter
id="helloJMSAdapater" destination="helloJMSQueue" connection-factory="jmsConnectionfactory"
channel="helloChannel" extract-payload="true" />
<integration:channel id="helloChannel" />
My requirement is to consume from here and post it to Kafka outbound adapter. Using the below config:
<int-kafka:outbound-channel-adapter
id="kafkaOutboundChannelAdapter"
kafka-producer-context-ref="kafkaProducerContext"
channel="inputToKafka">
</int-kafka:outbound-channel-adapter>
Here are what i want to achieve:
My queue is a durable topic and dont want to acknowledge the records unless it is successfully published to Kafka. In short, i want to have a transaction behaviour from consuming message from jms to publishing it to Kafka.
I noticed that my messages are immediately dequeued and if processing encounters some exception, i am unable to reprocess it. I dont want that to happen.
Also, when kafka encounters some issue, i want it to be returned to some method so that i can persist the failure message and as said before does not want to acknowledge it.
I am really struggling to get it to work. Can someone please help me out?
You really can have transaction-manager on the <jms:message-driven-channel-adapter> to start TX.
When <int-kafka:outbound-channel-adapter> throws an exception it causes the TX to be ralled back and therefore the message will be requeued.
If you are interested in the persisting errors, there is an error-channel option on the <jms:message-driven-channel-adapter>, but you still have to re-throw exception to let TX to rallback.
To make all that to work you should be sure that there is only single thread from the begging to the end. No <queue> or executor channel in the flow.
Also it isn't clear why do you use so old Apache Kafka still...

Inserting messages in a JMS queue and then sending back the acknowledgement using Spring Integration

I have a service which receives xml messages via an http inbound adapter and then transforms them into text that becomes the content of an email that gets sent out.
I now need to first insert these messages into a JMS queue and send the acknowledgement back as a 200 ok after the message is inserted into the Q and then carry-on with the rest of the processing.
<int-http:inbound-channel-adapter channel="inputChannel"
id="httpInbound"
auto-startup="true"
request-payload-type="java.lang.String"
path="/message"
supported-methods="POST"
error-channel="logger" >
<int-http:request-mapping consumes="application/xml" />
</int-http:inbound-channel-adapter>
<int:chain id="chain" input-channel="inputChannel" >
<int:service-activator ref="mailTransformerBean" method="transform" />
</int:chain>
The service-activator takes care of the processing to convert the xml into an email.
Before that I need to incorporate a JMS Queue into which the received messsages will be inserted and then the acknowledgement is sent back. This is so as to retain the messages and retry in case of a failure of the service.
I would like to set this up as a Transaction with the JMS queue as a endpoint.
How do i approach this?
If you are seeking something like a in-process persistence storage, take a look, please, into the SubscribableJmsChannel :
The channel in the above example will behave much like a normal <channel/> element from the main Spring Integration namespace. It can be referenced by both "input-channel" and "output-channel" attributes of any endpoint. The difference is that this channel is backed by a JMS Queue instance named "exampleQueue".

How to restart the message consumer in Spring Integration?

My consumer, e.g. service activator that is consuming messages coming from ActiveMQ fromChannel should be restarted when exception occurs or ActiveMQ fails. How to do it for the following spring integration context ?
<!-- RECEIVER. message driven adapter -> jmsInChannel -> activator. -->
<si:channel id="fromChannel"/>
<int-jms:message-driven-channel-adapter id="messageDrivenAdapter"
channel="fromChannel" destination="forward" connection-factory="connectionFactory"
max-concurrent-consumers="2" auto-startup="true" acknowledge="auto" extract-payload="false" />
<si:service-activator id ="activator"
input-channel="fromChannel"
ref="messageService"
method="process"/>
<bean id="messageService" class="com.ucware.ucpo.forward.jms.MessageService"/>
My first idea was to use Retry Advice and add to a service but am not sure if this a right solution for unhandled exceptions. I also would like the receiver to restart if the ActiveMQ server is down.
The listener container within the message-driven-channel-adapter will automatically keep trying to reconnect when it loses connectivity to the broker.
If you set `acknowledge="transacted"' the message will be rolled back on an exception and the broker will resubmit it.
A stateful retry advice would allow you to give up and take some other action after some number of retries (but you can also configure that into ActiveMQ itself where it will send the message to a DLQ after some number of delivery attempts).
Reading your post I instantly thought of this video. Which gives a good insight on how to monitor and control SI application through itself.
Additionally you should have a look at ApplicationEvent documentation of SI.
Glueing that all together you could monitor the JMS message adapter with JMX and stop and restart it through sending an ApplicationEvent on issues. Regarding catching exceptions it depends on what Exceptions you actually want to handle. I'd create an errorChannel that receives exceptions being thrown by components and create a new service that restarts these components after receiving errors.
Following your idea leveraging Spring Retry's capabilites in SI.

How to stop exception propagation if jms broker is down when sending a message with spring integration?

I configured spring xml based interceptor, which sends a jms message to activemq queue on each invokation of some transactional method after it is commited. It's happening with the following xml code.
<jms:outbound-channel-adapter channel="filteredStakesChannel" destination="stakesQueue" delivery-persistent="true" explicit-qos-enabled="true" />
But if the activemq server is down i get connection refused exception, which is propagated and i don't want this to happen even if the jms delivery fails. Is this possible?
Should i use some error-channel?
The simplest solution is to make fileredStakesChannel an Executor channel and the send will run on a different thread.
http://static.springsource.org/spring-integration/reference/html/messaging-channels-section.html#executor-channel
http://static.springsource.org/spring-integration/reference/html/messaging-channels-section.html#channel-configuration-executorchannel
Use the <task/> namespace to define an executor to use.

Error Message in Active MQ

I am sending xml messages over the activemq queue using Camel route. Message is reaching to the queue but its not able to read it. Not sure if it is a apache camel issue or Active MQ issue.
My camel route is
<route>
<from uri="seda:elixirBatchQueue" />
<inOnly uri="activemq:queue:TESTQUEUE"/>
</route>
Error Message in the queue is
javax.jms.JMSException: Failed to build body from bytes. Reason: java.io.StreamCorruptedException: invalid type code: 00
The problem was with ActiveMQ as it was not able to understand the message format. When I converted it to String, Queue was able to recognize message as a DOM4J document.
Try this it works for me.
producer.Send(objectMessage.Body);
The library I used -->> Apache.NMS.ActiveMQ

Resources