I am routing a message from queue->converting it using xslt and forwarding it to another queue, log.
My Camel configuration is as follows:
<camelContext xmlns="http://camel.apache.org/schema/spring"
streamCache="true">
<route>
<from uri="jms:queue:TradeEventsToESBQueue" />
<multicast>
<to uri="xslt:com/tpt/esb/tradeevent/confirmation.xsl" />
<to uri="xslt:com/tpt/esb/tradeevent/valuation.xsl" />
</multicast>
</route>
<route>
<from uri="xslt:com/tpt/esb/tradeevent/confirmation.xsl" />
<to uri="log:output?showAll=true" />
</route>
<route>
<from uri="xslt:com/tpt/esb/tradeevent/valuation.xsl" />
<to uri="jms:queue:TradeValuationStartQueue1?jmsMessageType=Text" />
<to uri="log:output?showAll=true" />
</route>
</camelContext>
On running the program i get the following error:
Caused by: org.apache.camel.ExpectedBodyTypeException: Could not
extract IN message body as type: interface javax.xml.transform.Source
body is: null at
org.apache.camel.builder.xml.XsltBuilder.getSource(XsltBuilder.java:482)[64:org.apache.camel.camel-core:2.10.1]
at
org.apache.camel.builder.xml.XsltBuilder.process(XsltBuilder.java:125)[64:org.apache.camel.camel-core:2.10.1]
at
org.apache.camel.impl.ProcessorPollingConsumer.receive(ProcessorPollingConsumer.java:58)[64:org.apache.camel.camel-core:2.10.1]
Any ideas what is causing this issue?
You should not use the XSLT component in that manner.
You should particularly not try to use "from" with XSLT, but rather use it in combination with any internal transport component (directly for the instance). I think the following will do what you want.
<route>
<from uri="jms:queue:TradeEventsToESBQueue" />
<multicast>
<to uri="direct:confirmation"/>
<to uri="direct:valuation"/>
</multicast>
</route>
<route>
<from uri="direct:confirmation"/>
<to uri="xslt:com/tpt/esb/tradeevent/confirmation.xsl" />
<to uri="log:output?showAll=true" />
</route>
<route>
<from uri="direct:valuation"/>
<to uri="xslt:com/tpt/esb/tradeevent/valuation.xsl" />
<to uri="jms:queue:TradeValuationStartQueue1?jmsMessageType=Text" />
<to uri="log:output?showAll=true" />
</route>
Related
I have a route from which I am trying to call a seda queue. I wanted to use a property which has been set in my current route to the seda queue. The below is the piece of code that I have been used, but it doesn't seems to be working as expected.
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="route1">
<!-- Method initialize the JobDetails class with values jobName="jobTest" and jobMode="mode1" -->
<bean ref="jobDetails" method="createJobDetails"/>
<to uri="activemq:queue:myqueue?disableReplyTo=true" />
</route>
<route id="route2">
<from uri="activemq:queue:myqueue" />
<convertBodyTo type="my.package.JobDetails" />
<setProperty propertyName="JOB_DETAILS">
<simple>${body}</simple>
</setProperty>
<recipientList>
<simple>direct-vm:testDirect-${property.JOB_DETAILS.jobName}</simple>
</recipientList>
</route>
</camelContext>
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="route3">
<from uri="direct-vm:testDirect-jobTest" />
<!-- Some business logic based on the job mode-->
<setProperty propertyName="JOB_MODE">
<simple>mode1</simple>
</setProperty>
<to uri="seda:testSeda?blockWhenFull=true" />
</route>
<route id="sedaRoute">
<from uri="seda:testSeda?concurrentConsumers=5" />
<log message="Message from firstRoute: ${property.JOB_MODE}" />
<!-- Perform some business logic based on the job mode -->
</route>
</camelContext>
Appreciated help!!!
I have following camel routing configuration.
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<!-- Rest Configuration -->
<restConfiguration component="jetty" port="9092" bindingMode="auto">
<dataFormatProperty key="json.in.disableFeatures" value="FAIL_ON_UNKNOWN_PROPERTIES" />
</restConfiguration>
<rest path="/" consumes="application/json"
produces="application/json">
<post uri="/" type="com.aaa.xxxx.esb.config.xxxxEsbJsonMapping">
<route>
<setHeader headerName="Authorization">
<simple>Basic YWRtaXXXXWRtaW4=</simple>
</setHeader>
<setHeader headerName="CamelHttpMethod">
<constant>POST</constant>
</setHeader>
<setHeader headerName="CamelHttpMethod">
<constant>POST</constant>
</setHeader>
<setHeader headerName="RestEndpointURL">
<simple>
http://${body.serviceURL}?bridgeEndpoint=true
</simple>
</setHeader>
<setBody>
<simple>{"UserDetails": ${body.serviceDataJsonObj}}</simple>
</setBody>
<log message="Exchanged headers : ${headers.RestEndpointURL}" />
<recipientList>
<simple>${headers.RestEndpointURL}</simple>
</recipientList>
</route>
</post>
</rest>
What I need to know is where I can set
matchOnUriPrefix=true
option for the jetty component which I have already configured for camel rest.
According to the Claus Ibsen answer, I changed configuration XML as follows.
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<!-- Rest Configuration -->
<restConfiguration component="jetty" port="9092"
bindingMode="auto">
<dataFormatProperty key="json.in.disableFeatures"
value="FAIL_ON_UNKNOWN_PROPERTIES" />
<componentProperty key="matchOnUriPrefix" value="true" />
</restConfiguration>
<!-- Rest Services -->
<rest path="/" consumes="application/json" produces="application/json">
<post uri="/" type="com.aaa.xxxx.esb.config.xxxxEsbJsonMapping">
<route>
<setHeader headerName="Authorization">
<simple>Basic YWRXXX46YWRtaW4=</simple>
</setHeader>
<setHeader headerName="CamelHttpMethod">
<constant>POST</constant>
</setHeader>
<setHeader headerName="CamelHttpMethod">
<constant>POST</constant>
</setHeader>
<setHeader headerName="RestEndpointURL">
<simple>
http://${body.serviceURL}?bridgeEndpoint=true
</simple>
</setHeader>
<setBody>
<simple>{"SystemUserDetails": ${body.serviceDataJsonObj}}</simple>
</setBody>
<log message="Exchanged headers : ${headers.RestEndpointURL}" />
<recipientList>
<simple>${headers.RestEndpointURL}</simple>
</recipientList>
</route>
</post>
</rest>
</camelContext>
I'm using servicemix apache-servicemix-7.0.0.M2
I upgraded its camel ver 2.16.3 to 2.17.3
Thanks
The rest-dsl is configured using the componentProperty in the restConfiguration:
<restConfiguration component="jetty" port="9092" bindingMode="auto">
<componentProperty key="matchOnUriPrefix" value="true"/>
<dataFormatProperty key="json.in.disableFeatures" value="FAIL_ON_UNKNOWN_PROPERTIES" />
</restConfiguration>
You can find details about this in the documentation: http://camel.apache.org/rest-dsl
U may add inside
route
tag as below:
<route>
<from uri="jetty://foo?matchOnUriPrefix=true"/>
...
</route>
I am looking out for a way by which a route can obtain and release a lock on another route, Below is my code snippet and I am looking for a solution where snmp-trap-route and snmp-timer-route can obtain an exclusive lock on business-logic-route and while one is processing other should wait till it completion.
<route id="snmp-trap-route">
<from uri="snmp:{{snmp.host}}:{{snmp.port}}?protocol=udp&type=TRAP" />
<to uri="direct:snmp-main-route"/>
<route id="snmp-timer-route">
<from uri="timer://pulse?fixedRate=true&period=1000" />
<to uri="direct:snmp-main-route"/>
<route id="snmp-main-route">
<from uri="direct:snmp-main-route" />
<choice>
<when>
<simple>${property[batch.ended]} == true </simple>
<to uri="direct:transacted-endpoint" />
</when>
<when>
<simple>${property[batch.started]} == true </simple>
<to uri="direct:business-logic-endpoint" />
</when>
<otherwise>
<to uri="direct:business-logic-endpoint" />
</otherwise>
</choice>
</route>
<route id="business-logic-route">
<from uri="direct:business-logic-endpoint"/>
<setProperty propertyName="route.name">
<constant>TestRoute</constant>
</setProperty>
<process ref="messageMultiplierProcessor" />
<process ref="calculatedFieldsProcessor" />
<process ref="tableProcessor" />
</route>
<route id="transacted-route">
<from uri="direct:transacted-endpoint"/>
<transacted/>
<to uri="direct:business-logic-endpoint"/>
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<rollback markRollbackOnly="true"/>
</onException>
</route>
You could reach the same result by using a queue.
A queue processes the messages 1-by-1. You can use the Seda component to achieve this if your route is in the same camelcontext. Otherwise you can use activemq
<route id="snmp-trap-route">
<from uri="snmp:{{snmp.host}}:{{snmp.port}}?protocol=udp&type=TRAP" />
<to uri="seda:business-logic-route"/>
<route id="snmp-timer-route">
<from uri="timer://pulse?fixedRate=true&period=1000" />
<to uri="seda:business-logic-route"/>
<route id="business-logic-route">
<from uri="seda:business-logic-endpoint"/>
<setProperty propertyName="esq.route.name">
<constant>TestRoute</constant>
</setProperty>
<process ref="messageMultiplierProcessor" />
<process ref="calculatedFieldsProcessor" />
This way the next message in the business-logic-route will only be processed after the business-logic-route is finished. Maybe this is what you are looking for.
How transactions works in Camel routes with Spring DSL and one of the route throws Exception?
If routeB throws an exception, how exception will be propagated back to routeA.
If exception is thrown in routeB, I could see transactionalErrorHandler is handling the exception and rolling back the transaction.
Setting the errorHandlerRef="noErrorHandler" on routeB does not help.
How can we do this?
My Camel routes definition:
<route id="routeA">
<from uri="direct-vm:endpointA" />
<transacted />
<to uri="direct-vm:endPointB" />
<bean ref="beanA" method="save" />
<onException>
<exception>java.lang.Exception>
<handled><constant>true</constant></handled>
<bean ref="beanA" method="handleError" />
<rollback markRollbackOnly="true" />
</onException>
</route>
<route id="routeB">
<from uri="direct-vm:endPointB" />
<throwException ref="ex"/>
</route>
In camel the transacted command is simply a wrapper for the Spring TransactionTemplate, in that it will enlist the route in a transaction supplied by the PlatformTransactionManager. The only configuration option you get on the org.apache.camel.spring.spi.SpringTransactionPolicy is the propagation behaviour, so handling rollbacks etc must be done within the transacted route.
In this case you should catch the exception from route B, if it gets to the error handler then it is too late.
<route id="routeA">
<from uri="direct-vm:endpointA" />
<transacted/>
<doTry>
<to uri="direct-vm:endPointB" />
<doCatch>
<exception>java.lang.Exception</exception>
<bean ref="beanA" method="handleFail"/>
</doCatch>
<doFinally>
<bean ref="beanA" method="save" />
</doFinally>
</doTry>
</route>
<route id="routeB">
<from uri="direct-vm:endPointB" />
<throwException ref="ex"/>
</route>
I'm using Apache Camel 2.11.1. It seems that both xml definitions are not equivalent in Camel:
First definition:
<bean id="amq" class="org.apache.activemq.camel.component.ActiveMQComponent"
p:brokerURL="tcp://localhost:61616" p:transacted="true"
p:cacheLevelName="CACHE_CONSUMER" p:concurrentConsumers="20"
p:maxConcurrentConsumers="500" p:idleConsumerLimit="10" />
Second definition:
<bean id="amq" class="org.apache.camel.component.jms.JmsComponent"
p:configuration-ref="jmsConfig" p:transacted="true" p:cacheLevelName="CACHE_CONSUMER" />
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration"
p:connectionFactory-ref="nakedConnectionFactory"
p:concurrentConsumers="20" p:maxConcurrentConsumers="500"
p:idleConsumerLimit="10" />
<bean id="nakedConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="tcp://localhost:61616" />
Since the first definition works well on the following route, but the second doesn't.
<route>
<from uri="amq:example.MyQueue" />
<setHeader headerName="myRoutingSlipHeader">
<constant>amq:one#amq:two#amq:three#amq:four</constant>
</setHeader>
<log message="Makan" />
<setExchangePattern pattern="InOut" />
<routingSlip uriDelimiter="#">
<header>myRoutingSlipHeader</header>
</routingSlip>
<setExchangePattern pattern="InOnly" />
<log message="End: ${body}" />
</route>
<route>
<from uri="amq:one" />
<to uri="bean:helloBean?method=stepOne" />
</route>
<route>
<from uri="amq:two" />
<to uri="bean:helloBean?method=stepTwo" />
</route>
<route>
<from uri="amq:three" />
<to uri="bean:helloBean?method=stepThree" />
</route>
<route>
<from uri="amq:four" />
<to uri="bean:helloBean?method=stepFour" />
</route>
The second component definition causes hang during execution.
Seems to work fine for me. I did have to override the spring version with the created archetype. But I used this and it worked fine.
Please find my example project here :
https://github.com/jimternet/camel-activemq
<broker xmlns="http://activemq.apache.org/schema/core" useJmx="true"
persistent="false">
<transportConnectors>
<transportConnector uri="tcp://localhost:61616" />
</transportConnectors>
</broker>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="file:src/data?noop=true" />
<to uri="activemq:personnel.records" />
</route>
<route>
<from uri="activemq:personnel.records" />
<log message="${body}" />
<choice>
<when>
<xpath>/person/city = 'London'</xpath>
<to uri="file:target/messages/uk" />
</when>
<otherwise>
<to uri="file:target/messages/others" />
</otherwise>
</choice>
</route>
</camelContext>
<bean id="activemq" class="org.apache.camel.component.jms.JmsComponent"
p:configuration-ref="jmsConfig" p:transacted="true" p:cacheLevelName="CACHE_CONSUMER" />
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration"
p:connectionFactory-ref="nakedConnectionFactory"
p:concurrentConsumers="20" p:maxConcurrentConsumers="500"
p:idleConsumerLimit="10" />
<bean id="nakedConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="tcp://localhost:61616" />