jboss fuse xquery custom functions - apache-camel

We have existing xqueries which we want to re use in our new JBoss fuse integration applications. As part of that I am trying to use XQuery component of JBoss Fuse 6.3. My question is how to pass arguments to my XQuery Function. This is my camel context
<camelContext id="dataConsumer-context" xmlns="http://camel.apache.org/schema/blueprint">
<propertyPlaceholder id="properties" location="classpath:sql.properties"/>
<route id="consumer-route">
<from id="_from1" uri="activemq:queue:house"/>
<log id="inputMessage" message="Got ${body}"/>
<to id="_to1" uri="xquery:myXquery.xquery"/>
<log id="transformedMessgae" message="Got ${body}"/>
<to id="_to2" uri="sql:{{sql.insertIntoMessage}}"/>
<log id="_log2" message="Message is inserted into DB"/>
</route>
</camelContext>
In myXquery.xquery this is the function I have
declare function xf:myPayments($pmtAddInp1 as element(ns0:PmtAddInp),
$header as element(*), $PaymentConstants as element(*)) as element() { }
declare variable $pmtAddInp1 as element(ns0:PmtAddInp) external;
declare variable $header as element(*) external;
declare variable $PaymentConstants as element(*) external;
xf:myPayments($pmtAddInp1,$header,$PaymentConstants)
I really appreciate if anybody can answer my question.

Everything in the Camel Exchange is visible to your XQuery. For example, you can put the desired arguments as headers within your Camel Route, then within your XQuery you define them as declare variable $in.headers.myArgumentKey as xs:string external; and they will be available for your functions to use directly as a variable called $in.headers.myArgumentKey

In addition to Gerry's answer:
body passes to XQuery component as root element.
Let say I have inbound body as
<Auth>
<userName>JohnDoe</userName>
<userPassword>abcd1234</userPassword>
</Auth>
then I can have XQuery to transform it and it may look like:
declare variable $in.headers.referenceId as xs:string external;
declare function transformRequest($requestBody as element()) as element() {
<newRequest>
<RqUID>{$in.headers.referenceId}</ser:RqUID>
<UserPrincipal>{$requestBody/userName/text()}</UserPrincipal>
<UserCredentials>{$requestBody/userPassword/text()}</UserCredentials>
</newRequest>
};
let $request := /*[1]
return buildNewRequest($request)
As you can see let $request := /*[1] sets internal variable $request to the root element of the message body.
PS. $in.headers.referenceId is a variable I can set into headers in Camel Route before calling my XQuery

Related

How to count substring instances in a exchange body

I have a body consisting of something like: OK,OK,NOK,OK,NOK, using Spring DSL.
I want to count the instances of substring 'OK' in the body. I tried StringHelper countChar, but you can only pass it chars.
Is there a way to count substrings in a body without resorting to java beans?
You can use bean to invoke an static method, such org.apache.commons.lang.StringUtils.countMatches to get the number of matches in the body:
from("direct:source")
.bean(StringUtils.class, "countMatches(${body}, OK)")
.to("log:org.orzowei.so.question.q69134695?level=WARN")
.end();
Or using Spring DSL:
<route id="abcRoute" autoStartup="true">
<from uri="direct:source"/>
<bean beanType="org.apache.commons.lang.StringUtils" method="countMatches(${body}, OK)"/>
<to uri="log:org.orzowei.so.question.q69134695?level=WARN"/>
</route>

Camel Component: setting a Property dynamically from a Bean

I have defined a Camel Route in a Jboss Fuse BluePrint. I'd need to set one variable at runtime from a Bean. See this example:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="wsClient">
<from uri="timer:foo?repeatCount=1" />
<setBody>
<simple>Message</simple>
</setBody>
<transform>
<method bean="myBean" method="transform" />
</transform>
<to uri="cxf:bean:MyWebService?defaultOperationName={{operation}}" />
<to uri="mock:result" />
</route>
</camelContext>
In this example, I'd like to set the property named "operation" within the bean "myBean". Is it possible to do it?
Thanks!
Yes, it is possible.
First, set a header from the bean and later use http://camel.apache.org/recipient-list.html
I am not familiar with Spring DSL, but in Java DSL it would look like this:
.recipientList(simple("cxf:bean:MyWebService?defaultOperationName=${header.operation}"))
Yes you can do that inside the bean. No need to pass any specific parameter. Camel can bind the exchange, body...etc as a method parameter automatically. Ref: http://camel.apache.org/bean-binding.html
using below code you can set the header or property
exchange.getIn().setHeader("HeaderName", "Value");
exchange.setProperty("Key", "Value");

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>

Apache Camel: Send empty body ws

How can i call a SOAP web service with an empty message body using Apache Camel?
For example, the final endpoint on a route would be the invocation of a method on my proxy that takes 0 arguments.
EDIT:
example xml configuration:
<route id="someRoute">
<from uri="ref:activemq-queue"/>
<setHeader headerName="operationName">
<constant>invoke</constant>
</setHeader>
<to uri="cxf:bean:someWS"/>
</route>
...
<cxf:cxfEndpoint id="someWS" address="${ws.address}"
serviceClass="com.example.ws.SomeWS"
The problem is that the method 'invoke' on the WS takes 0 arguments, and an exception is thrown stating that 1 argument is being received. Is there a way for me to specify to ignore this received input?
You can set the message body to be null, if the invocation just take 0 argument. null simple expression is added since camel 2.12.3.
<route id="someRoute">
<from uri="ref:activemq-queue"/>
<setBody>
<simple>null</simple>
</setBody>
<setHeader headerName="operationName">
<constant>invoke</constant>
</setHeader>
<to uri="cxf:bean:someWS"/>
</route>
I also needed to set an empty body to Apache Camel xml and the solution below worked for me.
<setBody id="set-empty-body">
<constant/>
</setBody>
Hope this helps to whoever need it.
The xml configuration will fail if the content of the body is not with the correct type of the class required by the method of your bean. By default, it could be an Object and not a String. When the method recieves the body in an incorrect format, it would process a null value, instead of the body of the route. To solve this problem, you will need to convert the body into the expected class of the method of your bean. For example, if the method's argument of the bean is a String, then you could do something like:
<route id="someRoute">
<from uri="ref:activemq-queue"/>
<setHeader headerName="operationName">
<constant>invoke</constant>
</setHeader>
<convertBodyTo type="String"/>
<to uri="cxf:bean:someWS"/>
</route>
For more information about body conversion, you can check the docs: https://camel.apache.org/components/3.14.x/eips/convertBodyTo-eip.html

How to extract value from Exchange object in camel esb

I have created a simple cxf web service. following is the body of soap message
<soapenv:Body>
<bean:getRTOEmployeeSalary>
<!--Optional:-->
<bean:arg0>sdf</bean:arg0>
</bean:getRTOEmployeeSalary>
</soapenv:Body>
My requirement is to extract the value of arg0 in my camel context file. i.e. i want to log the value of arg0. Please help me on this
<route routePolicyRef="loggingInInterceptor">
<from uri="cxf:bean:rtoemplyeeService"/>
<setHeader headerName="exchange">
<spel>${exchange}</spel>
</setHeader>
<log message="value of arg0======== "/>
<convertBodyTo type="java.lang.String" id="stringInput"/>
<bean ref="rtoEmpBean" method="getRTOEmployeeSalary" beanType="rtoEmpBean" id="govtRTOEmp"/>
</route>
I need to use the value of arg0 here.
We can use camel provided spring expression language to extract the value from exchange object. Since exchange object also resides in spring container.
below will be code src to extract the value of arg0 in camel context-
<setHeader headerName="arg0">
<spel>#{exchange.in.body.get(0)}</spel>
</setHeader>
This will set the value of arg0 of soap message in a header named arg0.
http://camel.apache.org/spel.html

Resources