How to call URL from Apache Camel in blueprint and return the data to a text file? - apache-camel

I am using Apache Camel blueprints, my route is triggered from a URL at port 8081 on localhost. This route generates a file but the problem is the file is a binary file without the HTML showing.
I then navigate my browser to http://localhost:8081/foo which triggers the URL.
What is it that I don't understand that is causing it to output a binary file rather than a text file? I guess that I must transform the body somehow?
<route id="url1">
<from uri="netty4-http:http://0.0.0.0:8081/foo" />
<to uri="http://www.google.com/?bridgeEndpoint=true" />
<to uri="file:/test"/>
</route>
Update: I think the problem is that the content coming back from www.google.com is gzip. When I look at the bridgeEndpoint parameter in the documentation it mentions something about gzip... now I am not sure, as I tried it on another website and it still doesn't work.
This line in my log might be relevant.
writing body: DefaultFullHttpResponse(decodeResult: success,
version: HTTP/1.1, content: UnpooledUnsafeDirectByteBuf(ridx: 0, widx: 0, cap: 0))
Update: I discover if I do:
<from uri="timer:secondfoo?period=20s" />
Replacing the from, then it works. Hmm... Something flowing from the netty4-http causes problem.
Update: I found something which works! Obsession pays off.
<route id="url1">
<from uri="netty-http:http://0.0.0.0:8081/foo" />
<removeHeaders pattern="*" />
<setBody>
<simple></simple>
</setBody>
<setHeader headerName="CamelHttpMethod">
<constant>GET</constant>
</setHeader>
<to uri="http://www.google.com/?bridgeEndpoint=true" />
<to uri="file:/test"/>
</route>

You can convert the message to a String type then its text based
<route id="url1">
<from uri="netty4-http:http://0.0.0.0:8081/foo" />
<to uri="http://www.google.com/?bridgeEndpoint=true" />
<convertBodyTo type="String"/>
<to uri="file:/test"/>
</route>

Related

Camel-Restlet producer message body is null

When invoking a rest endpoint using camel-restlet, the post body is not set.
Here is my blueprint.xml
<camelContext id="blueprint-bean-context-SF"
xmlns="http://camel.apache.org/schema/blueprint">
<route id="Camel-Restlet-Client">
<from uri="timer://example?repeatCount=1&period=1000" />
<setHeader headerName="Content-Type">
<constant>application/json</constant>
</setHeader>
<setHeader headerName="api-key">
<constant>{{drupal-api-key}}</constant>
</setHeader>
<setBody><constant>{name: "paul rudd", movies: ["I Love You Man", "Role Models"]}</constant></setBody>
<log message="Request: ${headers} \n ${body}" />
<to uri="restlet:https://reqres.in/api/users?restletMethod=POST" />
<log message="Response: ${headers} \n ${body}" />
</route>
</camelContext>
I am using camel 2.20.1. Any help is appreciated?
I am new to cmel myself, but i would guess the problem is the setHeader you are using. Because setHeader sets the header of the Camel-Message, not the header of the http-request which gets send over the wire. You would need to set a header on the message, that would be known by restlet. And restlet would transport the value of the setheader to the theader of the http-request.
Sorry but I dont how to do that. The following coding works, using the Header for authentification:
restConfiguration("restlet").bindingMode(RestBindingMode.json); // use json for all
from("timer://example?repeatCount=1&period=1000")
.setHeader("CamelRestletLogin", constant("xxx"))
.setHeader("CamelRestletPassword", constant("xxx"))
.to("restlet:https://xxx.hana.ondemand.com:443/ain/services/api/v1/models")
Sry I couldnt help more.

How to add scheduler and custome checks around camel file processing

Before explaining my problem I would state here that I am completely new to camel file processing. I have a requirement to read the file from a directory do some processing and delete them. This was a very high level requirement and I am able to achieve this using camel. But now I've got some new requirements as stated below. Need help on that.
Create this application as a job and trigger it by reading another directory where some specific files would be dropped other wise it should kicked of by its own every 15-20 minutes.
Before triggering the actual application make sure that the directory has some specific number of files present (say 25 files)
If all files are present - execute a method to create a unique tracking ID for all these 25 files. If I have a unique ID how can I make it available through multiple routes?
As of now I have tried implementing routepolicy but since I have never used it earlier I need some guidance so that I can go ahead with this.
1. Separe your route logic from route triggering
<route id="TriggerFromFile">
<from uri="file:triggerFolder" />
<log message="Triggered from file" />
<to uri="direct:startLogic" />
<route>
<route id="TriggerFromTimer">
<from uri="timer:triggerTimer?period=15m" />
<log message="Triggered from timer" />
<to uri="direct:startLogic" />
</route>
<route id="Logic>
<from uri="direct:startLogic" />
<to uri="..." />
</route>
2. Count the number of files and use that as a filter
Define a bean that counts the number of files in the dir, set that number
as body and validate using a filter.
<route id="TriggerFromFile">
<from uri="file:triggerFolder" />
<log message="Triggered from file" />
<to uri="direct:countFile" />
<route>
<route id="TriggerFromTimer">
<from uri="timer:triggerTimer?period=15m" />
<log message="Triggered from timer" />
<to uri="direct:countFile" />
</route>
<route id="FileCount">
<from uri="direct:countFile" />
<to uri="bean:countFilesInDir" />
<log message="There are ${body} files the directory" />
<filter>
<simple>${body} >= 25</simple>
<to uri="direct:startLogic" />
</filter>
</route>
<route id="Logic">
<from uri="direct:startLogic" />
<to uri="..." />
</route>
3. Set a Header to your Exchange's message before sending it to other routes
When Camel sends an Exchange between routes, headers and properties are copied.
Calculate a unique id in some way (concatenate file names, md5 of content, file modification timestamp....) and set it in a Header.
An header can hold any java object.

How to create a timer based camel polling route?

i created a route that is supposed to read from an OPC-UA endpoint. The read operation should be performed every second, based on a timer. Every example i found shows that the route can only have one from item. My route looks like this:
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="opctorest">
<from uri="timer://simpleTimer?period=1000"/>
<log message="Triggered Route: opctorest: Sensorreading body: ${body}"/>
<to uri="milo-client:tcp://0.0.0.0:4840/freeopcua/server?nodeId=2&namespaceUri=http://examples.freeopcua.github.io"/>
<convertBodyTo type="java.lang.String"/>
<to uri="stream:out"/>
</route>
</camelContext>
When i deploy the route, it gets called every second, but it writes to the endpoint, since the call is declared in a to element. How can i turn this into a read? I could not find a solution so far. Thanks!
Use the .enrich() to turn it into a read when you want to read in the middle of a route.
http://camel.apache.org/content-enricher.html
For your example something similar to (not tested):
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="opctorest">
<from uri="timer://simpleTimer?period=1000"/>
<log message="Triggered Route: opctorest: Sensorreading body: ${body}"/>
<enrich uri="milo-client:tcp://0.0.0.0:4840/freeopcua/server?nodeId=2&namespaceUri=http://examples.freeopcua.github.io"/>
<convertBodyTo type="java.lang.String"/>
<to uri="stream:out"/>
</route>
</camelContext>

Extracting the body from an ActiveMQ message via Camel

I have a route using the Spring DSL as such
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="activemq:queue:worker?mapJmsMessage=false" />
<convertBodyTo type="java.lang.String"/>
<setHeader headerName="CamelHttpMethod">
<constant>POST</constant>
</setHeader>
<to uri="http://localhost/queue" />
</route>
</camelContext>
The message type is an ActiveMQTextMessage. I am able to POST the message to the HTTP URL, but what I get seems to be the toString() output:
ActiveMQTextMessage {commandId = 5, responseRequired = false, message....
I would like to call the getText() method on the ActiveMQTextMessage instance to populate the route, but I cannot figure out how to get that method called. I am quite sure I could get this to work in code, but I need to do everything via XML.
Figured out the problem. I had mapJmsMessage=false set to handle an exception a few days ago. I removed it and suddenly it worked fine.

Camel File Endpoint - Getting the file name

I have a camel route:
from("file:///u01/www/images/nonprofits-test?move=.done&preMove=.processing&filter=#nonpFileFilter&minDepth=2&recursive=true")
Later on in the route I need to access the origin file name. How do I get that information? All of the headers contain information in like ${file:name}, but not the actual file name.
Thanks in advance!
The base problem is that simple language is not being evaluated correctly in while running Camel with grails. This is being discussed further on the Camel user list.
there is a header called "CamelFileName" that stores this
see camel-file2 headers section for more details...
If your simple language is not working it would be because you are not using <simple> tag try something like below.
<route id="movedFailedFileForRetry">
<from uri="file:///opt/failed?delete=true" />
<log loggingLevel="INFO" message="Moving failed file ${header.CamelFileName} for retry" />
<choice>
<when>
<simple>${headers.CamelFileName} == 'file1.txt'</simple>
<to uri="file:///opt/input1" />
</when>
<otherwise>
<to uri="file:///opt/input2" />
</otherwise>
</choice>
</route>
Hope it helps!!
${headers.CamelFileName} will provide you with the CamelFileName that is read for processing. We have many other header properties that you can find from the Camel Documentation.

Resources