How to set endpoint specific header value in Camel Multicast - apache-camel

I want to set the endpoint specific header value in Multicast component.
XML DSL as below:
<route>
<from uri="direct:testRoute"/>
<multicast strategyRef="MyAggregator" parallelProcessing="true">
<to uri="direct:call1"/> <!-- set the header MY_HEADER = "call_1" -->
<to uri="direct:call2/> <!-- set the header MY_HEADER = "call_2" -->
</multicast>
</route>
Basically in the response aggregation I want to know, to which service request this response belongs to.
I tried by doing this, but its not the correct way (parse exception):
<to uri="direct:call1">
<setHeader headerName="MY_HEADER"><simple>call1</simple></setHeader>
</to>
What I see from reading the documentation is that, multicast will copy the source Exchange and multicast each copy. So its a shallow copy of the Exchange and kind of reference shared between all the multicast recipient.
But here I am looking for specific header value for individual recipient.
How to do this? Any pointers?

You can't do that in the multicast route. But it should be simple in the direct route afterwards.
<route>
<from uri="direct:call1"/>
<setHeader headerName="MY_HEADER"><simple>call1</simple></setHeader>
.. do whatever
</from>
</route>
otherwise, if call1 is used for other things and you cannot know when to put the header once in that route, make a simple prep-route:
<route>
<from uri="direct:prepCall1"/>
<setHeader headerName="MY_HEADER"><simple>call1</simple></setHeader>
<to uri="direct:call1"/>
</from>
</route>
As a third option, even though you cannot place DSL (xml or java) in the multicast list, you can supply an "onPrepareRef" processor bean that adds the headers to your exchange. But one processor will handle all multicast endpoints.

There is a header with the key Exchange.TO_ENDPOINT that you can see which of the 2 endpoints the response is from.

Related

Set Headers in MULTICAST camel route

<route id="SUB2I0051">
<from uri="seda:SUB2-I0051MTMapper"/>
<multicast>
<to uri="file:C:/complexTest/?fileName=MT_Output.txt" />
<setHeader name="Node">
<simple>File1</simple>
</setHeader>
<to uri="audit:File1?level=info"/>
<to uri="file:C:/complexTest/?fileName=MTY_Output.txt" />
<setHeader name="Node">
<simple>File2</simple>
</setHeader>
<to uri="audit:File1?level=info"/>
</multicast>
</route>
I am trying to set headers inside the multicast tag. Headers need to be sent to an audit bean named as an audit. below is my route. Can anyone help me on this.
The Multicast EIP allows to route the same message to a number of endpoints and process them in a different way. its is important keyword is SAME.default multicast sync okey but camel dont send changed to to next node. u must call set header before multicast eip

Is it possible to create depedent route in camel

I have created multiple routes(say department, Employee) which takes input from file system folders(say department, Empployee) and process those files.
Now, I want to make them dependent. So, if I upload both emp.csv and dept.csv in those folders then it will process department file first and once complete it will start processing file for employee.
is there any way in camel to achieve this.
I looked at Route startupOrdering and AutoStartup feature, but it will work only for the first time when starting routes. However, I need same behavior for entire route life.
Thanks.
<route id="b" xmlns="http://camel.apache.org/schema/spring">
<from uri="file:/home/dev/code/Integration/RunCamleExample/src/main/resources/csv/Department?repeatCount=1&noop=true&delay=10000"/>
<log message="Department data is : ${body}"/>
</route>
<route id="employee" xmlns="http://camel.apache.org/schema/spring">
<from uri="file:/home/dev/code/Integration/RunCamleExample/src/main/resources/csv/Employee?noop=true&delay=10000"/>
<log message="Employee data is : ${body}"/>
</route>
I suggest to use other logic to handle the task. Two simple ways to go:
Use pollEnrich
Use pollEnrich to collect extra resource (e.g. a file with known name in file system) once at the middle of a route
Flow: Collect department files (From Endpoint) --(for each department file from file system) -> collect single employee file (trigger pollEnrich once with known name) ----> do anything else (if any)
Use ControlBus
Use ControlBus component to control the status of routes (only one of the route in 'start' status)
Flow: Start route A --(when route A complete its goal)-> Suspend route A ---> Start route B --(when route B complete its goal)-> Suspend route B ---> Start route A [loop back to head]
Dependent route execution first can be achieved in Camel using "RouteContext".
Example: If route 'A' is executed before route 'B' then route 'A' should be defined as 'RouteContext' and route be is defined inside "camelContext" like below:
<routeContext id="A" xmlns="http://camel.apache.org/schema/spring">
<route id="A">
<from uri="file:/home/dev/code/Integration/RunCamleExample/src/main/resources/csv/Department?repeatCount=1&noop=true&delay=10000"/>
<log message="Department data is : ${body}"/>
</route>
</routeContext>
Then regular "camelContext" should be defined with reference to this routeContext first.
<camelContext id="test" xmlns="http://camel.apache.org/schema/spring">
<routeContextRef ref="A"/>
<route id="B">
<from uri="file:/home/dev/code/Integration/RunCamleExample/src/main/resources/csv/Employee?noop=true&delay=10000"/>
<log message="Employee data is : ${body}"/>
</route>
</camelContext>

Is it possible to read a file after receiving an event?

I'm using a ActiveMQ Broker with built-in Camel Routes. I want to read a file after an Event received.
<pseudo>
from Event A
read File XY
to Event B with Body from File XY
</pseuod>
I simple tried moving files from a temporary directory based on an event but only event B is written. In the Log file are no Exceptions or Error messages.
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<!-- You can use Spring XML syntax to define the routes here using the <route> element -->
<route>
<description>Example Camel Route</description>
<from uri="activemq:example.A"/>
<from uri="file://tmp/a?delete=true"/>
<to uri="file://tmp/b?overruleFile=copy-of-${file:name}"/>
<to uri="activemq:example.B"/>
</route>
</camelContext>
Update with working solution for single file:
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<!-- You can use Spring XML syntax to define the routes here using the <route> element -->
<route>
<description>Example Camel Route</description>
<from uri="activemq:example.A"/>
<pollEnrich>
<constant>file:///tmp/a?fileName=file1</constant>
</pollEnrich>
<log message="file content ${body}"/>
<to uri="activemq:example.B"/>
</route>
</camelContext>
You need to use Content Enrichers for this. This is exactly what you are looking for.
<route>
<from uri="activemq:example.A"/>
<pollEnrich>
<constant>file://tmp/a?delete=true</constant>
</pollEnrich>
<to uri="activemq:example.B"/>
</route>
Please be aware that for camel version 2.15 or older
pollEnrich does not access any data from the current Exchange which
means when polling it cannot use any of the existing headers you may
have set on the Exchange. For example you cannot set a filename in the
Exchange.FILE_NAME header and use pollEnrich to consume only that
file. For that you must set the filename in the endpoint URI.

infinite message delivery loop with activeMQ and Broker Camel Component

I'm using activeMQ 5.9.
I'm trying to implement an interception type route in my activemq.xml, where I check if a particular header equals some value then send it to a different queue, otherwise allow it to continue.
I'm following the info here: http://activemq.apache.org/broker-camel-component.html
My camel.xml file looks like this:
<camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/spring">
<route id="routeAboveQueueLimitTest">
<from uri="activemq:queue:do.something"/>
<choice>
<when>
<simple>${header.scope} == 'test'</simple>
<to uri="activemq:queue:test.do.something"/>
</when>
<otherwise>
<to uri="activemq:queue:do.something"/>
</otherwise>
</choice>
</route>
</camelContext>
Then when I put a message on "activemq:queue:do.something" with header called scope = "test" it correctly routes to the "activemq:queue:test.do.something" queue. However, when it doesn't have that header, it puts it back on the "activemq:queue:do.something" queue and processes it again and again and again!
That kind of seems logical, but the above page clearly says that you have to explicitly send it back to the broker component, and the 2nd example on the page shows exactly that.
I realise this could be worked around by sending it to a different queue if it doesn't have the header but that is undesirable at this stage.
I think the intercept pattern would be much better suited for what you are looking.
<intercept>
<when><simple>${header.scope} == 'test'</simple></when>
<to uri="activemq:queue:test.do.something"/>
</intercept>
More info here: http://camel.apache.org/intercept.html
This will allow messages without the scope header set to 'test' to continue, but will redirect messages that do have the test header.
InterceptSendToEndpoint is a better option here...
<interceptSendToEndpoint uri="activemq:queue:do.something">
<when><simple>${header.scope} == 'test'</simple></when>
<to uri="activemq:queue:test.do.something"/>
<stop/>
</interceptSendToEndpoint>

Apache Camel transform not working

I have this Camel Route:
<route id="externalRestPushRoute">
<from uri="jms:pushProcessedRecordsToExternal" />
<setHeader headerName="PAYLOAD">
<simple>body</simple>
</setHeader>
<marshal ref="jack"></marshal>
<to uri="http://localhost/front/rest/karec/dummy-push"/>
<transform>
<simple>in.header[PAYLOAD]</simple>
</transform>
<to uri="bean:noAuthRecordPersistenceService?method=deliverySuccess" />
</route>
The idea is this:
I want to deliver an object in JSON format to a REST endpoint(all the headers are properly set and the rest endpoint receives the json format)/
To convert the object to JSON format I use marshal and it works.
Now, the response back from the http endpoint is of type java.io.InputStream but I don't care.
What I care is converting the body back to the original object before it was marshaled.
I did save the object in a header before marshaling in a header named PAYLOAD.
Now I want to use transform to get it back into the body of the message.
Well, that does not seem to work. When it get to the last bean it complains that body is still of type java.io.InputStream.
Stores the body on the exchange property instead of a header, that is safer.
<setProperty propertyName="PAYLOAD">
<simple>body</simple>
</setProperty>
<transform>
<simple>${property.PAYLOAD}</simple>
</transform>

Resources