How to extract value from Exchange object in camel esb - apache-camel

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

Related

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.

How can i add the options of a REST call to a header as a parameter?

I am using an ESB to route data between SQL and REST calls. So far this is working fine, however when i want to add options to the REST call. For example:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<propertyPlaceholder id="placeholder"
location="file:${karaf.home}/etc/nl.test.astron.sql.cfg" />
<restConfiguration bindingMode="json" component="servlet">
<endpointProperty key="servletName" value="ASTRONServlet" />
</restConfiguration>
<rest path="/get/astrondata">
<get uri="">
<to pattern="InOut" uri="direct:get" />
</get>
</rest>
<route id="get_to_uri">
<from uri="direct:get"/>
<setHeader headerName="boundRaMin">
<simple>70</simple>
</setHeader>
<setHeader headerName="boundRaMax">
<simple>90</simple>
</setHeader>
<setHeader headerName="boundDecMin">
<simple>0</simple>
</setHeader>
<setHeader headerName="boundDecMax">
<simple>30</simple>
</setHeader>
<to uri="sql:{{sql.getDatabase}}?
outputType=SelectList&
greedy=true&
useIterator=false"/>
</route>
and the SQL code is:
sql.getDatabase=SElECT * FROM dbo.astron_data WHERE :#boundRaMin<ra AND
ra<:#boundRaMax AND :#boundDecMin<dec AND dec<:#boundDecMax
As one can see here, boundRaMin,boundRaMax,boundDecMin,boundDecMax are all set by in the headers, However i want to make these variable depending on the options defined in the rest call. Thus for example the following call:
http://localhost:8080/astron/get/astrondata?boundRaMin=value1&boundRaMax=value2&boundDecMin=value3&boundDecMax=value4
should fill the right values of value1...value4 into the headers. It seems that these query parameters do not get mapped to the headers.
According to camel-sql component, from Camel 2.14 onward you can use Simple expressions. Thus try to modify the property placeholder sql.getDatabase to the following:
sql.getDatabase=SELECT * FROM dbo.astron_data WHERE :${header.boundRaMin} < ra AND
ra < ${header.boundRaMax} AND ${header.boundDecMin} < dec AND dec < ${header.boundDecMax}

Camel JMS - Unable to set JMSPriority to IBM MQ Message

We are trying to send JMS text message over IBM mq using Apache Camel. We are able set few JMS header properties except the JMSPriority. We tried setting int value and used resultType="java.lang.Integer" but unable to alter priority. Any clue would be more than helpful.
<route id="mqSender">
<from uri="direct:mqSender"></from>
<filter>
<simple> ${body} != null</simple>
<setProperty propertyName="originalRequest">
<simple> ${body}</simple>
</setProperty>
<setHeader headerName="JMSCorrelationID">
<simple>${body.messageContextVO.requestID}</simple>
</setHeader>
<setHeader headerName="VersionId">
<simple>${body.metadata["VersionId"]}</simple>
</setHeader>
<setHeader headerName="FunctionId">
<simple>${body.metadata["FunctionId"]}</simple>
</setHeader>
<setHeader headerName="Format">
<simple>${body.metadata["Format"]}</simple>
</setHeader>
<choice>
<when>
<simple>${property.originalRequest.metadata["FetchPriorityValue"]}== "true"</simple>
<transform>
<simple>${body.formattedData}</simple>
</transform>
<setHeader headerName="JMSPriority">
<simple> ${property.originalRequest.priority}</simple>
</setHeader>
<camel:setHeader headerName="CamelJmsDestinationName"><simple>queue:///${property.originalRequest.metadata["queueName"]}?targetClient=1</simple></camel:setHeader>
</when>
</choice>
<log message="${property.originalRequest.metadata[queueName]}"></log>
<recipientList>
<simple>wmq:queue:${property.originalRequest.metadata["queueName"]}?exchangePattern=InOnly</simple>
</recipientList>
<transform>
<simple>${property.originalRequest}</simple>
</transform>
</filter>
<!-- <to uri="bean:trackerUpdateProcessor?method=process" /> -->
</route>
We found solution to make it work. Priority attribute is required to set at header CamelJmsDestinationName
i.e,
<camel:setHeader headerName="CamelJmsDestinationName"><simple>queue:///${property.originalRequest.metadata["queueName"]}?targetClient=1&priority=${dynamicValue}</simple></camel:setHeader>
Sender code checks for value of priority at MQ Destination level in native code. TimeToLive and Priority values needs to set at MQ destination level to work with Camel.
I am not sure about wmq, but for normal jms component (and I believe camel wmq behave the same) to set JMSPriority for specific message endpoint configuration must have option "preserveMessageQos" set to true
Set to true, if you want to send message using the QoS settings specified on the message, instead of the QoS settings on the JMS endpoint. The following three headers are considered JMSPriority, JMSDeliveryMode, and JMSExpiration. You can provide all or only some of them. If not provided, Camel will fall back to use the values from the endpoint instead. So, when using this option, the headers override the values from the endpoint. The explicitQosEnabled option, by contrast, will only use options set on the endpoint, and not values from the message header.

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: 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

Resources