I have a situation where I want to route the incoming request to a proxy based on XPath if present in a message or not.
For example: Let us consider the two request to a proxy.
Request 1:
<PCSDetailProxyResponse>
<MarketDefinitionsRequest>
<![CDATA[Request elements TBD]]>
</MarketDefinitionsRequest>
</PCSDetailProxyResponse>
Request 2:
<PCSDetailProxyRequest>
<ReportParameterRequest>
<![CDATA[Request elements TBD]]>
</ReportParameterRequest>
</PCSDetailProxyRequest>
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="ReportParameterRequestEP">
</endpoint>
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="MarketDefinitionsRequest">
</endpoint>
I want to route the two requests to 2 different end points based on the kind of request ( MarketDefinitionsRequest or ReportParameterRequest).
If the request contains ReportParameterRequest then I want to send to ReportParameterRequestEP
If the request contains MarketDefinitionsRequest then I want to send to MarketDefinitionsRequestEP.
What should I do to identify if a request contains or element because based on that only I will have to take the routing decision?
I recommend using filter mediators for this:
<filter xpath="fn:exists($body/MarketDefinitionsRequest)">
<sequence key="MarketDefnitionsSequence"/>
</filter>
<filter xpath="fn:exists($body/ReportParameterRequest)">
<sequence key="ReportParameterSequence"/>
</filter>
You can then create separate sequences for processing the different scenarios.
If you were looking for the value of the content of a node, then the switch mediator would be easier. Because you're filtering on the name of the node, the exists function is necessary instead.
Related
i read at this url
https://docs.wso2.org/display/ESB480/Sample+157:+Conditional+Router+for+Routing+Messages+based+on+HTTP+URL,+HTTP+Headers+and+Query+Parameters
that conditional router matching a regex can be written like this:
<match type="header" source="my_custom_header2" regex="bar.*"/>
where type can be header, url or param.
Can be used the body message as source? i have to evaluate something like this:
<match type="????" source="json-eval($.codice)" regex="0"/>
where type should the message body. Is it possible? or have i to use the FILTER mediator? i mean something like:
<filter xpath="/codice='OK'">
<then>
//DO SOMETHING
</then>
<else>
DO ANOTHER THING
</else>
</filter>
Couple of things: Match only supports the types header, param and url. You will also not be able to use JSON Path on the match regardless of whether it supports message body.
You should go with filter if you are routing based on message body.
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>
New to Camel, and I'm trying to parse a response error xml. Within the camel-context I need to determine if a specific value exists in the error file, and handle it differently than other errors.
The other errors use a series of when statements:
<when>
<xpath>/abc:ErrorResponse/abc:Error/abc:Message/.</xpath>
<setHeader headerName="RESPONSE_STRING">
<xpath resultType="java.lang.String">/abc:ErrorResponse/abc:Error/abc:Message/.</xpath>
</setHeader>
<setHeader headerName="MY_DATA_FIELD"><constant>Error</constant></setHeader>
<to uri="def:doErrorStuff" pattern="InOnly"/>
</when>
<when>
<xpath>/ghi:ErrorResponse/ghi:Error/ghi:Message/.</xpath>
<setHeader headerName="RESPONSE_STRING">
<xpath resultType="java.lang.String">/ghi:ErrorResponse/ghi:Error/ghi:Message/.</xpath>
</setHeader>
<setHeader headerName="MY_DATA_FIELD"><constant>Error</constant></setHeader>
<to uri="def:doErrorStuff" pattern="InOnly"/>
</when>
My error XML file has an outer error element with child "Code" element. I need to parse the value of the code element
UPDATE: HERE IS THE XML I AM PARSING
<ErrorResponse xmlns="http://myhost/location1/">
<Error>
<Type>reserved</Type>
<Code>TEXT_I_NEED_TO_PARSE_IN_WHEN_STATEMENT</Code>
</Error>
<RequestId>some_id</RequestId>
</ErrorResponse>
I used a combination of xpath and 'simple' to make the check. Like this:
<when>
<xpath>/ghi:ErrorResponse/ghi:Error/ghi:Message/.</xpath>
<when>
<simple>${in.body.code} == 'StringIAmSearchingFor'</simple>
<!-- Do Stuff --!>
</when>
</when>
However, I am not getting the response I expect.
1. Is there something wrong with this approach or the syntax?
2. Is there a way to combine the double when layout so they are and-ed together. Otherwise, if I add my "when" statement just ahead of the existing two, the existing "ghi" when statement will never get executed (the xpath statements match).
You are using xpath on your input suggesting that it's XML, then simple (${in.body.code}) which in that case also would be XML. Simple is used to traverse java bodies and not other formats such as XML. Stick to XPATH all the way - your code above can easily be implemented in xpath. Another way, of course, would be to unmarshal the XML into java objects using xstream or jaxb, then you can use only simple/OGNL/groovy or whatnot.
Since I recommend you to solve this very case with xpath alone, you can of course use the xpath and operator to and several xpath expressions together. All logic and power in camel choice/when reside in the expression language you are using (be it simple or xpath), so if you want to mix expression languages, you have to build up sort of a decision tree. That could actually be something good if you are trying to implement very complex routing logic. For a single special case - it's, IMHO, just messy.
I'm hoping someone can explain a bit more about how to configure Camel to marshal and unmarshal data. I have a route that calls a bean in order to determine a recipientList. This is based on the contents of the message (a protobuf).
The route config looks like:-
<route id="Splitter">
<from uri="activemq:notification.splitter" />
<unmarshal ref="notificationProto" />
<recipientList>
<method bean="NotificationSplitter" method="splitNotification" />
</recipientList>
</route>
The bean works fine, but the downstream routes complain that:-
org.apache.camel.RuntimeCamelException: java.lang.RuntimeException: Unable to find proto buffer class
The downstream routes have exactly the same protobuf dataFormat config as the route above. If I route directly to the downstream queues (i.e. bypass the bean and hardcode the "to" queues), which means I can also skip the unmarshalling step, it works fine.
I guess that I need to re-marshal the data before Camel puts the messages onto the destination queues but I don't know how to configure this within the XML. I've tried simply adding...
<marshal ref="notificationProto" />
...after the recipientList has been determined but it doesn't do it (I assume because Camel has already dispatched the messages by then).
An alternative could be to do the unmarshalling from within the bean as then the data on the exchange will presumably remain unaltered. I'm not quite sure how to do this. Would it work?
Thanks for any tips.
J.
Yeah the data formats are not an endpoint that's easy to send a message to, as otherwise you can use the Routing Slip EIP pattern instead, and send the message to the data format first, and then the destination. http://camel.apache.org/routing-slip.html
Though you could have a little route
<route>
<from uri="direct:marshalMe"/>
<marshal ref="notificationProto" />
</route>
And then use the routing slip, to set to "direct:marshalMe,whereYouWannaGoNext".
An alternative is to use an interceptor, and intercept sending to endpoints (you can filter by wildcards, or reg exps), and then do the marshal first. http://camel.apache.org/intercept
See that link for more details.
I have a service need to validate parameters. For example,my request is:
<purchasePackage xmlns="http://bss.internal.service.boss.sysway.com/">
<entitlementId xmlns="">20100812151324</entitlementId>
<subscriberId xmlns="" />
<packageId xmlns="">SZ_VOD</packageId>
<deviceId xmlns="">801830456396</deviceId>
<effectionTime xmlns="">2010-08-25 00:00:00</effectionTime>
<expirationTime xmlns="">2009-08-25 00:00:00</expirationTime>
</purchasePackage>
EffectionTime is later than expirationTime, so I need response a error message out instead of send it to real service. How to do this?Someone can give me some advises?Best regards.
Use WSO2 ESB server and define custom proxy. When proxy receives the above request, pick both date values using xpath (use filter mediator) and compare which is greater value. You can use XPATh function for that(date comparison)
if greater allow to send to the service ..else execute fault sequence..
http://wso2.org/project/esb/java/4.0.3/docs/mediators/filter.html