Apache camel: data from exchange header to another route - spring

I have to ask about camel route behaviour, which is silly (but simple to understand) logical description.
In main themes - i need to push info from exchange header of one route to another one.
It's all about CMDB system and monitoring tool zabbix.
Well, at the first i have a route which can switch CI state in CMDB:
<route>
<description> route catching CI ID in jms queue, check it on exist and switch CI state to incident
</description>
<from uri="jms:switchCIStateQueue"/>
<filter>
<simple>${body} regex '[\d]+'</simple>
<to uri="bean:otrsCIApi?method=getCIBodyByID(${body})"/>
<filter>
<simple>${body} regex '\{.+?\}'</simple>
<marshal>
<json library="Jackson"/>
</marshal>
<unmarshal>
<json library="Jackson" unmarshalTypeName="ts.team.otrs.ci.OtrsCI"/>
</unmarshal>
<to uri="bean:otrsCIApi?method=switchOTRSCIState(${body})"/>
</filter>
</filter>
</route>
It's working good, but i have to use this action from another route, which have many checks, filters and choices.
My problem is that i don't have a CI ID as a body (but keep it in header) in depth of main logical route.
<route>
<description>Route catch triggerid
and creates a ticket in OTRS, link it to host
</description>
<from uri="direct:zab_trig_2_otrs_tick"/>
<to uri="bean:zabbixApi?method=getTriggerByID(body)"/>
<filter>
<simple>${body} regex '\{.+?\}'</simple>
<marshal>
<json library="Jackson"/>
</marshal>
<unmarshal>
<json library="Jackson" unmarshalTypeName="ts.team.zabbix.trigger.SingleTrigger"/>
</unmarshal>
<setHeader headerName="ZabbixTrigger" id="_setZabbixTrigger">
<simple>${body}</simple>
</setHeader>
<!-- search CI in OTRS -->
<to uri="bean:otrsCIApi?method=searchCI(${body.getHosts().get(0).getName()})"/>
<!-- Array of CI ID like [] or ["1"] -->
<split streaming="true">
<simple>${body}</simple>
<!-- place it in header-->
<setHeader headerName="HostID">
<simple>${body}</simple>
</setHeader>
<to uri="bean:otrsLinkApi?method=ListLinkedTicketsTitleFiltered(${body},${header.ZabbixTrigger.getDescription()})"/>
<!-- return JSONArray with State=open otrs Tickets ID -->
<choice>
<when id="ticketslist_empty">
<simple>${body} == ''</simple>
<!-- Create ticket, connect it to host in OTRS -->
<to uri="bean:otrsTicketApi?method=createNewTicket(${header.ZabbixTrigger.getDescription()},${header.ZabbixTrigger.getPriority()})"/>
<!-- return body body with ticket id, create link with ${header.HostID} -->
<to uri="bean:otrsLinkApi?method=LinkAdd(${header.HostID},${body})"/>
<!-- Here i need to switch CI state if incident priority is higher than 3(Normal)-->
<when>
<simple>${header.ZabbixTrigger.getPriority()} > 3</simple>
<!-- here i need to send ${header.HostID} to previous described route (jms:switchCIStateQueue)-->
</when>
</when>
</choice>
</split>
</filter>
</route>
So, there is piece of this route:
<when>
<simple>${header.ZabbixTrigger.getPriority()} > 3</simple>
<!-- here i need to send ${header.HostID} to previous described route (jms:switchCIStateQueue)-->
</when>
where i need to send some info from my header to jms:switchCIStateQueue (or route direct, it's no matter where to).
I hope, my description of problem is quite full and simple.

OK.
You asked two questions:
i need to push CIID into first described route
You have to push a jms message to jms:switchCIStateQueue
so, in your source route (second "big one") it should be like:
<to uri="jms:switchCIStateQueue"/>
whatever is in Exchange headers will be in JMS message headers. Exchange message body will be JMS message body.
if you will do it in source route with code as is, there will be JMS header HostID and your first route which gets that JMS message has access to it as ${header.HostID}
Then depends on what your otrsCIApi.getCIBodyByID expects and does your call may look like
a. <to uri="bean:otrsCIApi?method=getCIBodyByID(${header.HostID})"/>
b. But if expected parameter for 'getCIBodyByID' has a different structure/format with something more that CIID you have to build it properly either when you send it to the queue (in "big" route) or after you get a message from queue.
How can i place ${header.HostID} into body
again it depends on what is a structure/format of expected JMS message body
a. just place HostID header value in the body as is:
<when>
<simple>${header.ZabbixTrigger.getPriority()} > 3</simple>
<!-- here i set ${header.HostID} into body -->
<body>
<simple>${header.HostID}</simple>
</body>
<!-- here i can set ${header.HostID} into another header if i'd like to -->
<setHeader headerName="CIID">
<simple>${header.HostID}</simple>
</setHeader>
<!-- finally I send message to queue -->
<to uri="jms:switchCIStateQueue"/>
</when>
b. Something more than just CIID value - build it as needed (in place of <body> element there could be processor or another bean method call which will do that.
Did I understand your questions properly and is it what you are looking for?

Related

How to retrieve value from cxf RAW message using xpath

Below is my code snippet for Camel Context in Spring DSL. I can retrieve
value from PAYLOAD message but not able to retrieve using RAW. Is there any way we can retrieve value from RAW message which is a SOAP request XML?
<cxf:cxfEndpoint address="/xxx/xxx/xxx/xxx/" endpointName="vi:nameService" id="SOAPInput"
serviceName="vi:nameService" wsdlURL="wsdl/name.wsdl" xmlns:vi="http://services.visa.com/xx/xx/xx/xxx">
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
<from id="Listener" uri="cxf:bean:SOAPInput?dataFormat=RAW"/>
<setProperty id="setName" propertyName="name">
<xpath resultType="java.lang.String" trim="false">/*/*/*/v1:getname/name/text()</xpath>
</setProperty>

Loop with apache camel

I am expecting multiple operation in one request. I need to to loop the xml to to do the following using Apache camel route.
1) get the total opertions in request xml and put in variable.
2) get total number of expression using xpath on xml and put in list
3) loop with (total number of operation ) times to evaluate the expression
First step would be list nodeList = /tractscation/operations
<loop>
<constant>nodeLIst.length</xpath>
compare and execute operation
</loop>
Above lines are just psuedo code, i want anybody help me with exact code using camel Xpath and loop. .
I am new to xpath and camel. we are using camelxpath spring DSL
if you want to loop through each node matching the xpath and process it individually, then use camel-splitter EIP...
<route>
<from uri="direct:a"/>
<split>
<xpath>/transaction/operations</xpath>
<to uri="direct:b"/>
</split>
</route>
otherwise, there is a camel-loop EIP that can be used to execute the same process a variable number of times...but the splitter is generally used for parsing/looping type of operations
from("direct:c").loop().xpath("/hello/#times").to("mock:result");
I hope it helps you =D
Inside route
<to uri="direct:WSCall" />
<split strategyRef="groupExchangeAggregationStrategy">
<xpath>//response/operation</xpath>
</split>
Velocity template
<tag>
#foreach( $exchangeItem in ${body} )
${exchangeItem.in.body}
#end
</tag>
Include
<beans>
<bean id="groupExchangeAggregationStrategy" class="org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy" />
</beans>

dynamic parameter to an endpoint

How to set a dynamic value as a parameter to an endpoint?
Payload :
<person>
<name>john</name>
<acno>9876543210</acno>
</person>
route :
<route>
<from uri="http://localhost:8092/test/"/>
<setProperty propertyName="acno">
<xpath resultType="java.lang.String">//person/acno</xpath>
</setProperty>
<setProperty propertyName="name">
<xpath resultType="java.lang.String">//person/name</xpath>
</setProperty>
<to uri="https://server/rest/services/test?accountno=${property.acno}&accountname=${property.name}"/>
</route>
The parameter value want to take from the payload by xpath.
Any help in resolving this issue or providing a workaround would be very appreciated.
You can't use dynamic content from headers inside endpoint URIs.
What you can do is to preconstruct the URI by using some xpath or whatever and put it into a header. Then you can use the Recipient List construct to use that dynamicly created URI.
You have some examples in the link
Update: see this link suggested by Claus Ibsen in comment

JMSExpiration vs TimeToLive

I'm trying to set message expiration within a Blueprint XML Camel route. The value I want to set as the expiration is held within the message body (a protobuf).
Here's my code:-
<setHeader headerName="AMQ_SCHEDULED_DELAY">
<method bean="NotificationScheduler" method="postponeSending" />
</setHeader>
<setHeader headerName="JMSExpiration">
<method bean="NotificationScheduler" method="getExpiry" />
</setHeader>
<setHeader headerName="ExpirationTest">
<method bean="NotificationScheduler" method="getExpiry" />
</setHeader>
<to uri="activemq:notifications.splitter" />
As you can see from the screen shot below, I'm successfully setting two of the three headers but the setting for "JMSExpiration" (as per this thread) has had no effect.
I know I could alternatively use the Recipient List pattern to dynamically set the uri - i.e. pull the expiry out of the message data and append the ?timeToLive=... option. However, this seems a little clunky to me.
Is there a way to set expiration via setHeader within the XML?
Thanks,
J.
Change your uri to: activemq:notifications.splitter?preserveMessageQos=true and you should be fine.
Some JMS headers can be "manually" overriden like you are trying to by using this option.
Please note that you might want to take some precausion, since if you are listening on one JMS endpoint, the arriving messages will have JMS headers populated, and when you send the message out in your "to", the message will keep JMSDeliveryMode, JMSExpiration and JMSPriority. This might or might not be what you want.

Apache Camel: how extract parameter from incoming HTTP message (with XML body)

I am trying to use CAMEL as HTTP proxy and I would like to extract a parameter from an incoming HTTP message with a XML body. This parameter I would then like to add in the header of a HTTP POST message towards another endpoint (another server).
Example: the XML body contains a parameter called "subscriptionId". The value of this field "subscriptionId" is then to be used in the uri of the outgoing HTTP POST message.
So, if subscriptionId=1234567, I want the uri in the HTTP POST message to be like:
POST /webapp/createnewsubscription?subscriptionId=1234567
I am using Spring DSL to create my Camel routes.
Anyone an idea how to do this ?
Thanks,
Jan
I presume you want to POST to first URL with XML as payload.
First you would need to use XPath component to get value for your XML tag and then setBody to pass parameter to proxied request (optionally you could switch from POST to GET).
Something like this should work:
<route>
<from uri="jetty:http://127.0.0.1:8080/myapp"/>
<setHeader headerName="subscriptionId">
<xpath resultType="java.lang.String">//subscriptionId/text()</xpath>
</setHeader>
<!-- if you need to convert from POST to GET
<setHeader headerName="CamelHttpMethod">
<constant>GET</constant>
</setHeader>
-->
<setBody>
<simple>subscriptionId=${in.headers.subscriptionId}</simple>
</setBody>
<to uri="jetty:http://127.0.0.1:8090/myapp?bridgeEndpoint=true&throwExceptionOnFailure=false"/>
</route>
You should be able to test it from command line say with wget:
$ cat 1.txt
<a>
<subscriptionId>123</subscriptionId>
</a>
$ wget --post-file=1.txt --header="Content-Type:text/xml" http://127.0.0.1:8080/myapp
You could use second route to test responses like this:
<route>
<from uri="jetty:http://127.0.0.1:8090/myapp"/>
<to uri="log:mylog?level=INFO"/>
<setBody>
<simple>OK: ${in.headers.CamelHttpMethod}: ${in.headers.subscriptionId}</simple>
</setBody>
</route>
And if you set camelContext to 'trace' you should see lots of info in your log of what's going on on every step of the processing:
<camel:camelContext id="camel" trace="true" xmlns="http://camel.apache.org/schema/spring">

Resources