How to make Camel pattern="InOut" work with IBM MQ - apache-camel

As described here:
setting ReplyToQ attribute of MQMD of IBM MQ request message with Camel
I managed to set ReplyToQ in MQMD of request properly in Camel Route, but I can't get the response in the same Route, with the IBM MQ Endpoint ("to") that I would like to use both for output (of request) and for input (of response), because it is matching wrong Correlation ID, like this:
The OUT message was not received within: 20000 millis due reply message with correlationID: Camel-ID-MYPC-62418-1518179436629-0-5 not received on destination: queue:///REPLYQ. Exchange[ID-MYPC-62418-1518179436629-0-4]
Namely, responding application sets CorrelationID (in MQMD) to the MessageID (from MQMD of the received request). How to make this scenario work?
I tried with useMessageIDAsCorrelationID, but this doesn't change much the result (responses are not consumed). Another try was to set MessageID of request to some fixed value (that would not be final solution), but I can't even do that. I added this:
<setHeader headerName="JMSMessageID" id="_setHeader2">
<constant>abcdefg</constant>
</setHeader>
<setHeader headerName="JMSCorrelationID" id="_setHeader3">
<constant>abcdefg</constant>
</setHeader>
but this only sets CorrelationID, and I still get such things:
The OUT message was not received within: 20000 millis due reply message with correlationID: abcdefg not received on destination: queue:///REPLYQ. Exchange[ID-MYPC-65151-1518190285422-0-3]
Complete route definition:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean class="org.apache.camel.component.jms.JmsComponent" id="websphere">
<property name="connectionFactory">
<bean class="com.ibm.mq.jms.MQConnectionFactory">
<property name="transportType" value="1"/>
<property name="hostName" value="hostname"/>
<property name="port" value="port"/>
<property name="queueManager" value="qmgr_name"/>
<property name="channel" value="channel_name"/>
</bean>
</property>
</bean>
<!-- Define a traditional camel context here -->
<camelContext id="camel" useBreadcrumb="false" xmlns="http://camel.apache.org/schema/spring">
<route id="simple-route">
<from id="request-file" uri="file://C:/mqdocuments/?fileName=request.txt"/>
<log id="route-log" message=">>> ${body}"/>
<setHeader headerName="CamelJmsDestinationName" id="_setHeader1">
<constant>queue://QM_TEST/INPUTQ?targetClient=1&mdWriteEnabled=true&mdReadEnabled=true</constant>
</setHeader>
<setHeader headerName="JMSMessageID" id="_setHeader2">
<constant>abcdefg</constant>
</setHeader>
<setHeader headerName="JMSCorrelationID" id="_setHeader3">
<constant>abcdefg</constant>
</setHeader>
<to id="_to1" pattern="InOut" uri="websphere:queue:SYSTEM.DEFAULT.LOCAL.QUEUE?replyTo=REPLYQ"/>
</route>
</camelContext>
</beans>

OK, this simple code actually works as explained here:
http://camel.apache.org/correlation-identifier.html
<route id="simple-route">
<from id="request-file" uri="file://C:/mqdocuments/?fileName=request464.txt"/>
<log id="route-log-request" message="request: ${body}"/>
<setHeader headerName="CamelJmsDestinationName" id="_setHeader1">
<constant>queue://QM_TEST/INPUTQ?targetClient=1</constant>
</setHeader>
<to id="_to1" pattern="InOut" uri="websphere:queue:SYSTEM.DEFAULT.LOCAL.QUEUE?useMessageIDAsCorrelationID=true&replyTo=REPLYQ"/>
<log id="route-log-response" message="response: ${body}"/>
</route>
It prints out neatly response body to console output.
I don't know why I was under impression that it doesn't work when I first tried it. So, to summarize both questions, the catch is in using useMessageIDAsCorrelationID and replyTo parameters in uri of a queue, as well as pattern="InOut" parameter of <to> endpoint.

Related

Camel errorHandler doesn't log before or after sending message to the dead letter channel

We have a simple Camel route like below. But we have noticed that errorHandler log is not working. After some investigation, we understood that errorHandler has different log parameters then other logs(like in route or onException).
We haven't succeeded to use errorHandler log. Yes, there are so many options to log but we want to learn how to use this one. Our aim is to log some texts before or after sending messages to deadletter queue.
How can we use errorHandler log?
apache-camel : 3.19.0
spring-boot : 2.7.5
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="mdcEnricher" class="com.mycompany.MDCEnricher"/>
<camel:camelContext id="mycontext" xmlns="http://camel.apache.org/schema/spring" useMDCLogging="true">
<camel:errorHandler id="myErrorHandler" type="DeadLetterChannel"
useOriginalBody="true"
deadLetterUri="jms:queue:mybackoutq">
<redeliveryPolicy
maximumRedeliveries="1"
redeliveryDelay="1"
retryAttemptedLogLevel="WARN"
retriesExhaustedLogLevel="ERROR"/>
<log id="logIncomingMsg" logName="com.mypackage"
loggingLevel="ERROR" message="Pushing to backout queue"/>
</camel:errorHandler>
<camel:route id="myRoute" errorHandlerRef="myErrorHandler">
<from uri="jms:queue:myinputq"/>
<bean ref="mdcEnricher" method="enrich"/>
<log message="Received exchange with message id: [${headers.JMSMessageID}], starting processing"/>
<process ref="#class:com.mycompany.processor.MyProcessor"/>
<to uri="jms:queue:myoutputq"/>
<log message="Finished the processing exchange with message id: [${headers.JMSMessageID}]"/>
</camel:route>
Try to change log configuration and loggingLevel to DEBUG but nothing changed.
<springProfile name="local">
<logger name="org.apache.camel" level="DEBUG"/>
<logger name="com.mycompany" level="DEBUG"/>
<root level="DEBUG">
<appender-ref ref="LocalConsole"/>
</root>
</springProfile>

Camel blueprint <setHeader headerName="CamelHttpPath" id="_setHeader1"><el>${header.uriPattern}</el></setHeader> waiting for dependencies

I have the following Camel Context.
<camelContext id="_camuatomicservicecontext" xmlns="http://camel.apache.org/schema/blueprint">
<route id="_camuatomicserviceroute1">
<from id="_from1" uri="direct-vm:camuatomicservice">
<description>accepts vm messages directly </description>
</from>
<log id="_log1" message="Camu Atomic Service body = ${body}, header= ${header.uriPattern}"/>
<!-- <to id="_to1" uri="restlet:protocol:localhost:8189/"/> -->
<setHeader headerName="api.key" id="_setHeader1">
<constant>replace later with properties api.key Does not matter for this poc</constant>
</setHeader>
<setHeader headerName="CamelHttpPath" id="_setOutHeader1">
<el>${header.uriPattern}</el>
</setHeader>
<to id="_to1" pattern="InOut" uri="netty4-http:http:localhost:8189/path"/>
<log id="_log2" message="CamuAtomicService Response body ${body}"/>
</route>
</camelContext>
From the documentation I expect the CamelHttpPath header to override the endpoint configuration "/path" such that calling Facade Services can pass the header.uriPattern in and dynamically change the resource they want to access. The bundle worked fine until I added the setHeader for CamelHttpPath and now getting "Waiting for dependencies." I assume I need to install a feature, but Simple EL in other bundles on that server work already so not sure what feature I need to install.
Instead of I used and it worked fine. The choice was farther down in the options.

How can i add the options of a REST call to a header as a parameter?

I am using an ESB to route data between SQL and REST calls. So far this is working fine, however when i want to add options to the REST call. For example:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<propertyPlaceholder id="placeholder"
location="file:${karaf.home}/etc/nl.test.astron.sql.cfg" />
<restConfiguration bindingMode="json" component="servlet">
<endpointProperty key="servletName" value="ASTRONServlet" />
</restConfiguration>
<rest path="/get/astrondata">
<get uri="">
<to pattern="InOut" uri="direct:get" />
</get>
</rest>
<route id="get_to_uri">
<from uri="direct:get"/>
<setHeader headerName="boundRaMin">
<simple>70</simple>
</setHeader>
<setHeader headerName="boundRaMax">
<simple>90</simple>
</setHeader>
<setHeader headerName="boundDecMin">
<simple>0</simple>
</setHeader>
<setHeader headerName="boundDecMax">
<simple>30</simple>
</setHeader>
<to uri="sql:{{sql.getDatabase}}?
outputType=SelectList&
greedy=true&
useIterator=false"/>
</route>
and the SQL code is:
sql.getDatabase=SElECT * FROM dbo.astron_data WHERE :#boundRaMin<ra AND
ra<:#boundRaMax AND :#boundDecMin<dec AND dec<:#boundDecMax
As one can see here, boundRaMin,boundRaMax,boundDecMin,boundDecMax are all set by in the headers, However i want to make these variable depending on the options defined in the rest call. Thus for example the following call:
http://localhost:8080/astron/get/astrondata?boundRaMin=value1&boundRaMax=value2&boundDecMin=value3&boundDecMax=value4
should fill the right values of value1...value4 into the headers. It seems that these query parameters do not get mapped to the headers.
According to camel-sql component, from Camel 2.14 onward you can use Simple expressions. Thus try to modify the property placeholder sql.getDatabase to the following:
sql.getDatabase=SELECT * FROM dbo.astron_data WHERE :${header.boundRaMin} < ra AND
ra < ${header.boundRaMax} AND ${header.boundDecMin} < dec AND dec < ${header.boundDecMax}

How to create a timer based camel polling route?

i created a route that is supposed to read from an OPC-UA endpoint. The read operation should be performed every second, based on a timer. Every example i found shows that the route can only have one from item. My route looks like this:
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="opctorest">
<from uri="timer://simpleTimer?period=1000"/>
<log message="Triggered Route: opctorest: Sensorreading body: ${body}"/>
<to uri="milo-client:tcp://0.0.0.0:4840/freeopcua/server?nodeId=2&namespaceUri=http://examples.freeopcua.github.io"/>
<convertBodyTo type="java.lang.String"/>
<to uri="stream:out"/>
</route>
</camelContext>
When i deploy the route, it gets called every second, but it writes to the endpoint, since the call is declared in a to element. How can i turn this into a read? I could not find a solution so far. Thanks!
Use the .enrich() to turn it into a read when you want to read in the middle of a route.
http://camel.apache.org/content-enricher.html
For your example something similar to (not tested):
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="opctorest">
<from uri="timer://simpleTimer?period=1000"/>
<log message="Triggered Route: opctorest: Sensorreading body: ${body}"/>
<enrich uri="milo-client:tcp://0.0.0.0:4840/freeopcua/server?nodeId=2&namespaceUri=http://examples.freeopcua.github.io"/>
<convertBodyTo type="java.lang.String"/>
<to uri="stream:out"/>
</route>
</camelContext>

If route threw exception and handled is set to true, only first processor in doFinally is executed

I've got a Camel Blueprint definition with two Camel contexts containing one route each.
First contexts route is invoked and in turn calls the route of the second context. Now if in the second route an Exception is thrown and the onException sets handled=true, in the first routes doFinally block only the first processor is invoked.
Here is my Blueprint definition:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<bean id="myException" class="java.lang.RuntimeException">
<argument value="Booom" />
</bean>
<camelContext id="firstContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route id="firstRoute">
<from uri="direct-vm:start"/>
<doTry>
<to uri="log:FIRST_TRY"/>
<to uri="direct-vm:generateException"/>
<to uri="log:SECOND_TRY"/>
<doFinally>
<to uri="log:FIRST_FINALLY"/>
<to uri="log:SECOND_FINALLY"/>
</doFinally>
</doTry>
<log message="The message contains ${body}"/>
<to uri="mock:result"/>
</route>
</camelContext>
<camelContext id="secondContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
</onException>
<route id="secondRoute">
<from uri="direct-vm:generateException"/>
<throwException ref="myException"/>
</route>
</camelContext>
</blueprint>
Only the <to uri="log:FIRST_FINALLY"/> gets printed out. I cannot see the <to uri="log:SECOND_FINALLY"/>. Am I missing something here? Any help is appreciated.
I am using Camel 2.10.6 inside Apache Servicemix 4.5.2.
Regards
Dominik
You can consider using multicast [1] as a workaround for this issue.
<doFinally>
<multicast>
<to uri="log:FIRST_FINALLY"/>
<to uri="log:SECOND_FINALLY"/>
</multicast>
</doFinally>
This is not the same as pipeline processing of course, but in some cases doFinally block can just send two messages independently.
[1] http://camel.apache.org/multicast

Resources