I have been trying to come up with a camel route that would read from an activemq and write to Oracle AQ.
However, when a message is succesfully written to Oracle-aq, I have to write a successful message to another Active mq queue("something like message with id 41 has been sent to OracleAQ")
Is there any "Auto-acknowledge" type of feature in camel that can be useful here?
This is the basic route that i have that routes from active mq to oracle aq.
<route>
<from uri="jms:queue:Q.Customer1"/>
<setHeader headerName="prop">
<simple>header1Value</simple>
</setHeader>
<to uri="oracleQueue:queue:Q.Customer2"/>
</route>
Just add another to that points to the queue you want camel to post to after it writes to oracle, like so:
<onException>
<exception>some.sql.Exception</exception>
<to uri="some:error:handler:uri" /> <!-- like a bean or dead letter channel or whatever -->
</onException>
<route>
<from uri="jms:queue:Q.Customer1"/>
<setHeader headerName="prop">
<simple>header1Value</simple>
</setHeader>
<to uri="oracleQueue:queue:Q.Customer2"/>
<!-- this step will not be called until the previous one is finished -->
<to uri="jms:queue:SomeOtherQueue"/>
</route>
Related
We have a route that will accept the kafka.KEY and use that as mqtt url parameter to send the data to the right topic.
<routes
xmlns="http://camel.apache.org/schema/spring">
<route id="KafkaToMQTT">
<from uri="kafka://mqtt?brokers=localhost:9092"/>
<to uri="micrometer:timer:camel.proxy.kafka.mqtt.stream?action=start"/>
<log message="Headers ${header.kafka.KEY}"/>
<to uri="mqtt:mqtt?host=tcp://localhost:1883&publishTopicName=try${header.kafka.KEY}"/>
<to uri="log://camel.proxy?groupInterval=3&level=INFO"/>
<to uri="micrometer:timer:camel.proxy.kafka.mqtt.stream?action=stop"/>
</route>
</routes>
In the log messages I see the ${header.kafka.KEY} correctly, while in the mqtt I'm getting the topic as literally try${header.kafka.KEY}
What is the reason for that, how to make the header to be used there?
To avoid that the right element instead of to should be used, that is toD.
toD concatenates the url correctly, so the right route XML is:
<routes
xmlns="http://camel.apache.org/schema/spring">
<route id="KafkaToMQTT">
<from uri="kafka://mqtt?brokers=localhost:9092"/>
<to uri="micrometer:timer:camel.proxy.kafka.mqtt.stream?action=start"/>
<log message="Headers ${header.kafka.KEY}"/>
<toD uri="mqtt:mqtt?host=tcp://localhost:1883&publishTopicName=ESP_02/try${header.kafka.KEY}"/>
<to uri="log://camel.proxy?groupInterval=3&level=INFO"/>
<to uri="micrometer:timer:camel.proxy.kafka.mqtt.stream?action=stop"/>
</route>
</routes>
With route defined in Spring DSL:
<route>
<from uri="direct:load1" />
<loadBalance>
<failover roundRobin="true" maximumFailoverAttempts="1"/>
<to uri="broker1:queue:queue"/>
<to uri="broker2:queue:queue"/>
</loadBalance>
</route>
How would implement a custom error handler or processor to handle the out body when the failover exhausted the maximumFailoverAttempts?
To make it simpler to understand, both broker1 and broker2 endpoints are unavailable, a processor should then be invoked to set the out body to "failed" as an example.
Currently I'm using <doTry>
<route>
<from uri="direct:load1" />
<doTry>
<loadBalance>
<failover roundRobin="true" maximumFailoverAttempts="1"/>
<to uri="broker1:queue:queue1"/>
<to uri="broker1:queue:queue2"/>
</loadBalance>
<doCatch>
<exception>java.lang.Exception</exception>
<process ref="loadbalanceExceptionProcessor" />
</doCatch>
</doTry>
</route>
Is there a better approach to this?
A short question about Apache Camel.
I have the following scenario, where my server receives jms messages and then transform to csv file and then insert DB.
For this purpose i have 2 beans:
xml2csv
insertDB
I use routing like:
<route id="route1" errorHandlerRef="myErrorHandler">
<from uri="file://{someFolder1}}
?...
<to uri="bean:xml2csv" />
<log message="transformed to xml file" />
</route>
<route id="route2" errorHandlerRef="myErrorHandler">
<from uri="file://{{someFolder2}}
?...
<to uri="direct:csvOnboardingChannel" />
</route>
<route id="csvOnboarding" errorHandlerRef="myErrorHandler">
<from uri="direct:csvOnboardingChannel" />
<to uri="bean:insertDB" />
</route>
When "route" a file from-to, is it move like a message? or putting the question different, does Apache Camel take a file, wrap it as a message and route it to a bean or a component?
Do I understand it correct or am in a wrong directation.
Yes, your understanding is correct. Camel reads in the file's data and sends it as a message through the route to a bean. Might also be simpler as a single route, like so:
<route id="route1" errorHandlerRef="myErrorHandler">
<from uri="file://{someFolder1}}">
<to uri="bean:xml2csv" />
<to uri="bean:insertDB" />
</route>
I built a web service in apache camel running as a bundle on karaf which takes the requests and saves the information in a database.
After this another bundle takes this inserted record, modifies the data and saves it back to the db.
Now I need the response of the original request to contain the modified data so besides the route for the web service that looks like this
<route id="cxf">
<from uri="cxf:bean:getHopEndpoint" />
<recipientList>
<simple>direct:${header.operationName}</simple>
</recipientList>
</route>
<route id="getHop">
<from uri="direct:getHop" />
<process ref="getHopToDbProcessor" />
<to
uri="sql:INSERT INTO myTable (field1, field2) VALUES (:#field1, :#field2)"/>
</route>
I would need another one like this
<route id="cxfResponse">
<from uri="sql:SELECT * FROM myTable"/>
<!-- to web service response in any way -->
</route>
Is there any way to do this?
You would have to set the body to the desired response as the last step in the first route. There is no way to set the response outside this route.
So I think there are two way to solve your problem.
Do all you need to do inside the first route in a synchronous way
Change your service to be completely asynchronous
For Variant 2 you can either use messaging like jms or you give the first call a webservice uri to call back.
If you have high load on the service a completely async approach might make your system work better.
I found another solution: I'm using the Direct VM Component. My Routes look like this now:
Bundle 1 recieve web service request and save the data in the database:
<route id="cxf">
<from uri="cxf:bean:getHopEndpoint" />
<recipientList>
<simple>direct:${header.operationName}</simple>
</recipientList>
</route>
<route id="getHop">
<from uri="direct:getHop" />
<process ref="getHopToDbProcessor" />
<to uri="sql:INSERT INTO myTable (field1, field2) VALUES (:#field1, :#field2)" />
<to uri="direct-vm:processHop" />
</route>
In bundle 2 which processes the data I just inserted:
<route>
<from uri="direct-vm:processHop"/>
<to uri="sql:SELECT * FROM myTable WHERE processed = false" />
<process ref="getHopComputopUrlProcessor" />
<to uri="sql:UPDATE webshop_gethop_requests SET new_data = :#newData, processed = true WHERE some_id = :#someId" />
<to uri="direct-vm:response"/>
</route>
And then back to bundle 1 again to send the response with the processed data:
<route>
<from uri="direct-vm:response" />
<to uri="sql:SELECT some_id,new_data FROM myTable WHERE some_id = :#someId AND processed = true" />
<process ref="getHopResponseProcessor" />
</route>
This works just fine for me :)
I have a Camel route that dequeues a message off a queue, sends it to a bean for processing, then enqueues the message back onto a different queue.
I am trying to eliminate "duplicate messages" on the 2nd queue. Does Camel have any endpoints, processors, EIPs, etc. that I could configure to dedupe message en route, before they get sent to the 2nd queue?
Example:
<route id="myRoute">
<from uri="{{queue-1-uri}}" />
<to uri="bean:myBean?method=process" />
<!-- How to dedupe right here??? -->
<to uri="{{queue-2-uri}}" />
</route>
Update: perhaps something like this:
<route id="myRoute">
<from uri="{{queue-1-uri}}" />
<to uri="bean:myBean?method=process" />
<filter>
<method>what goes here???</method>
<to uri="{{queue-2-uri}}" />
</filter>
</route>
Per Ralf's suggestion, I could then reference a bean inside <method></method> that then used a cache to keep messages in memory.
Say this new bean was called FilterBean and it had a dedupe() method on it: how do I wire it up in the Spring XML, and what classes/interfaces does the bean need to implement to be called from inside the route?
I think you are looking for the Idempotent Consumer that Camel provides. There are different approaches depending on your needs like Memory, JDBC, Hazelcast... I am not really sure if it will work for you since you are using a bean after the consumer but it worth to give it a try. Simple example from Camel website is as follows:
<!-- repository for the idempotent consumer -->
<bean id="myRepo" class="org.apache.camel.processor.idempotent.MemoryIdempotentRepository"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<idempotentConsumer messageIdRepositoryRef="myRepo">
<!-- use the messageId header as key for identifying duplicate messages -->
<header>messageId</header>
<!-- if not a duplicate send it to this mock endpoint -->
<to uri="mock:result"/>
</idempotentConsumer>
</route>
</camelContext>
You can find more info here: Idempotent Consumer