Does Camel REST DSL work with a Restlet Servlet? - java

I recently upgraded to Camel 2.14.1 and have been playing around the new REST DSL. Before the upgrade I used restlet within a servlet container, i.e. with this in my web.xml:
<!-- Restlet Servlet -->
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>org.restlet.ext.spring.SpringServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.component</param-name>
<param-value>RestletComponent</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/rs/*</url-pattern>
</servlet-mapping>
And this in my camel context:
<bean id="RestletComponent" class="org.restlet.Component" />
<bean id="RestletComponentService" class="org.apache.camel.component.restlet.RestletComponent">
<constructor-arg index="0">
<ref bean="RestletComponent" />
</constructor-arg>
</bean>
This does not work with the REST DSL.
I'm testing it out with this simple route:
<rest>
<get uri="/hello">
<to uri="direct:hello"/>
</get>
</rest>
<route id="hello">
<from uri="direct:hello"/>
<setBody><constant>Dolly</constant></setBody>
</route>
The REST DSL successfully finds the RestletComponent Bean defined in my web.xml, but the bean does not have a camelContext associated with it, so I get a null pointer exception when the code tries to access the context.
Basically, I'm beginning to suspect that the REST DSL is incompatible with Restlet within a servlet container. I want the hosting servlet container to handle the incoming requests, I don't want to have to spawn a separate restlet server process (on a new port) for my camel contexts.
Am I out of luck?
OK, to make things easier, I started from one of the existing examples: camel-example-restlet-jdbc which uses restlet and altered it so it uses the new rest dsl.
Here's the xml-dsl.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<import resource="common.xml" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<rest>
<post uri="/persons">
<route>
<setBody>
<simple>insert into person(firstName, lastName) values('${header.firstName}','${header.lastName}')
</simple>
</setBody>
<to uri="jdbc:dataSource"/>
<setBody>
<!--<simple>select * from person ORDER BY id desc OFFSET 1 ROWS</simple>-->
<simple>select * from person where id in (select max(id) from person)</simple>
</setBody>
<to uri="jdbc:dataSource"/>
</route>
</post>
<get uri="/persons/{personId}">
<route>
<setBody>
<simple>select * from person where id = ${header.personId}</simple>
</setBody>
<to uri="jdbc:dataSource"/>
</route>
</get>
<get uri="/persons">
<route>
<setBody>
<constant>select * from person</constant>
</setBody>
<to uri="jdbc:dataSource"/>
</route>
</get>
</rest>
</camelContext>
</beans>
This doesn't work. It throws java.net.SocketException: Permission denied

I haven't used the Rest DSL before, but according to the documentation you can explicitly let Camel know that you are using the restlet component:
<restConfiguration component="RestletComponent" port="9091"> <componentProperty key="foo" value="123"/> </restConfiguration>
It does say that it will lookup to check whether there are any components that integrates with the DSL if this is not specified, but I guess but it's worth giving it a shot.
On a side note, I found it a bit odd that you give your spring beans IDs starting with an uppercase.

Related

Intercept and log incoming message to endpoint

I want to log the incoming SOAP in my beans setup but I don't know how to intercept the requested body.
I found out if I add ?dataFormat=MESSAGE to my CxfEndpoint it shows the xml input but messes up the dataFormat that provides the addBookTransformer.
<from uri="cxf:bean:CxfEndpoint?dataFormat=MESSAGE" />
This is my setup
<cxf:cxfEndpoint id="CxfEndpoint"
address="/host/addBook"
endpointName="a:addBookEndpoint"
serviceName="a:addBookService"
wsdlURL="wsdl/add-book.wsdl"
serviceClass="com.library.AddBookEndpoint"
xmlns:a="http://library.com"/>
<bean id="addBookTransformer" class="com.library.bookshelf.AddBookTransformer"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="addBook" streamCache="true">
<from uri="cxf:bean:CxfEndpoint" />
<process ref="addBookTransformer" />
<log message="${body}"/>
</route>
</camelContext>
Is there a way to itercept and log the incoming post request data?
You could do wiretap for this
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="addBook" streamCache="true">
<from uri="cxf:bean:CxfEndpoint" />
<process ref="addBookTransformer" />
<wireTap uri="direct:tap"/>
<to uri="mock:result"/>
<log message="${body}"/>
</route>
</camelContext>
A copy of the exchange is sent to direct:tap which you can read and process however you want.
For example we could just log the message like this. You could also add another processor.
<route id="wiretapped" streamCache="true">
<from uri="direct:tap" />
<log message="${body}"/>
</route>
Here is the documentation for this.
What you are looking for is a very well known requirement. The pattern that provides the solution is a Filter and exists as a concept in the very early versions of J2EE spec. Back in times when we (the dinosaurs) wrote servlets, you could add a Filter to your servlet that intercepts both, request before it gets to your servlet and response after it is generated by your servlet but before it is sent to the client-side. In your Filter, you can log info, redirect it to a different destination, deny it or do anything you like. The same concept remains intact. You need to define a filter for all or some of your end-points and in your filter do the logging. If you work with Spring boot here is the article that describes how to add Filters for end-points in Spring Boot: How to Define a Spring Boot Filter?

How can i get the route from blueprint xml file

I have some problem. I need to take the route or all CamelContext from blueprint file. How can i did it?
route.xml
I have tried to add route via RouteDefinitions but it throws exceptions because it expected spring namespace but i use blueprint namespace. I use cxf as implementation of JAX-RS. There is another way how to do it better.
xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<bean id="weatherMailService" class="com.test.mail.MailSenderImpl"/>
<service ref="weatherMailService" interface="com.test.mail.MailSender"/>
<bean id="serviceProcessor" class="com.test.mail.MailSenderImpl"/>
<bean id="context" class="com.test.mail.MailSenderImpl"></bean>
<camelContext id="ctx" xmlns="http://camel.apache.org/schema/blueprint">
<route id="mail">
<from uri="direct:start"/>
<setBody>
<constant>Test</constant>
</setBody>
<setHeader headerName="subject">
<simple>Weather</simple>
</setHeader>
<process ref="serviceProcessor"/>
<to uri="smtps://smtp.gmail.com:465?username=RAW(*****#gmail.com)&password=******&to=******#gmail.com"/>
<to uri="log:start"/>
<process ref="context"></process>
</route>
</camelContext>
I would like to get CamelContext in java code. How can i did it? Thank you

override prepareOnStartup method in GenericFileProcessStrategy class

I'm using apache camel File in order to read a file from the file system into a bean method. I'm using it with spring xml . I need to override prepareOnStartup method in GenericFileProcessStrategy class on the route process .
Can you please tell me what is the Syntax to do it in the from uri route line in the spring xml file ?
the spring xml :
<bean id="adoFilter" class="calypsox.bllInterfaces.cashMgn.cashMgnAdo.AdoFileFilter"/>
<camelContext xmlns="http://camel.apache.org/schema/spring" id="cashMgn">
<propertyPlaceholder id="cashMgnProperty"
location="${bll.resources.env}/cashMgn.properties" />
<route id="cashMgnAdo">
<from uri="file:{{cashMgnAdoFileDir}}?filter=#adoFilter;move=.org/${date:now:yyyyMMdd}/${file:name}&readLock=changed&readLockCheckInterval=2000&readLockTimeout=10000&moveFailed=.failed" />
<convertBodyTo type="java.lang.String" />
<to uri="bean:cashMgnHandler?method=handleCashMgnAdo" />
</route>
</camelContext>
The GenericFileProcessStrategy can be set with the processStrategy property :
<bean id="myProcessStrategy" class="..."/>
..
<from uri="file:..?..processStrategy=#myProcessStrategy"/>

ServiceMix and Camel : How do I create routes?

This part of the puzzle is my nightmare, I have deployed ServiceMix, and 2 Java apps on 2 different tomcat instances :
First app :
http://localhost:8080/textmsgClient
Second app :
http://localhost:8181/textmsgServer
Now my two apps need to communicate, though I want that communication to go through ServiceMix, so I can do some logs and everything.
I've created a blueprint XML file in the ./deploy directory, but what routes should I put in them?
I can't do this :
<route>
<from uri="http://localhost:8080/textmsgClient"/>
<log message="Test log"/>
<to uri="http://localhost:8181/textmsgServer"/>
</route>
so what is the correct thing to do ?
by the way, my XML file looks like this :
<?xml version="1.0" encoding="UTF-8"?>
<blueprint
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route>
<from uri="file:camel/input"/>
<log message="Moving ${file:name} to the output directory"/>
<to uri="file:camel/output"/>
</route>
</camelContext>
</blueprint>
Take a look at the list of Camel Components. Not knowing what type of data you are sending between services, it is difficult to recommend which one to use. However, theres a component for pretty much every data type you can imagine, and even support to make your own!
Edit
An example might be:
<route>
<from uri="direct:textmsgClient"/>
<log message="Test log"/>
<to uri="direct:textmsgServer"/>
</route>

Camel EIP to filter duplicates

I have a Camel route that dequeues a message off a queue, sends it to a bean for processing, then enqueues the message back onto a different queue.
I am trying to eliminate "duplicate messages" on the 2nd queue. Does Camel have any endpoints, processors, EIPs, etc. that I could configure to dedupe message en route, before they get sent to the 2nd queue?
Example:
<route id="myRoute">
<from uri="{{queue-1-uri}}" />
<to uri="bean:myBean?method=process" />
<!-- How to dedupe right here??? -->
<to uri="{{queue-2-uri}}" />
</route>
Update: perhaps something like this:
<route id="myRoute">
<from uri="{{queue-1-uri}}" />
<to uri="bean:myBean?method=process" />
<filter>
<method>what goes here???</method>
<to uri="{{queue-2-uri}}" />
</filter>
</route>
Per Ralf's suggestion, I could then reference a bean inside <method></method> that then used a cache to keep messages in memory.
Say this new bean was called FilterBean and it had a dedupe() method on it: how do I wire it up in the Spring XML, and what classes/interfaces does the bean need to implement to be called from inside the route?
I think you are looking for the Idempotent Consumer that Camel provides. There are different approaches depending on your needs like Memory, JDBC, Hazelcast... I am not really sure if it will work for you since you are using a bean after the consumer but it worth to give it a try. Simple example from Camel website is as follows:
<!-- repository for the idempotent consumer -->
<bean id="myRepo" class="org.apache.camel.processor.idempotent.MemoryIdempotentRepository"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<idempotentConsumer messageIdRepositoryRef="myRepo">
<!-- use the messageId header as key for identifying duplicate messages -->
<header>messageId</header>
<!-- if not a duplicate send it to this mock endpoint -->
<to uri="mock:result"/>
</idempotentConsumer>
</route>
</camelContext>
You can find more info here: Idempotent Consumer

Categories