Using Camel to stream output from a POST to a URL - apache-camel

Is it possible to use the Camel Stream Component to read output of a POST to a URL? Something like: <to uri="stream:url?url=http://localhost:8080/mycontext/myservlet"/>
I tried this but it did not work. I need to post a JSON object to a URL and process a huge payload being returned, so I need it to be streamed to a file without loading it all in memory first. Are there alternatives in the CAMEL DSLs or should I be using a bean somehow, e.g. using a HttpUrlConnection, to do the streaming?

Simply use the http module - it does support POST requests and furthermore will give you an InputStream in return.
As long as your route does not force Camel to auto-convert the message payload to String, you are free to implement any proprietary streaming logic in your handler. In other words, make sure your handler, e.g. a bean method, uses InputStream rather than String in its method signature.

Related

Bridging http request with path variable in CAMEL REST

I am trying to bridge Camel REST endpoints to a backend server. Corresponding REST DSL is as follows:
from("rest:get:tt:/{id}")
.toF("%s/%s?bridgeEndpoint=true","http://192.168.1.1:80","jjjj/llll/pppp/{id}");
My expectation is that the request should be forwarded to http://192.168.1.1:80/jjjj/llll/pppp/id But what actually happens is that the request gets forwarded to http://192.168.1.1:80/jjjj/llll/pppp/%7Bid%7D/tt/id
Can any one suggest, what am I doing wrong and how I can achieve the desired behaviour? I am using Spring Boot Camel 2.3.4 which uses Camel 3.5.0 internally.
Mean while, I have found a work around that to use .to() instead of .toF(). With .to(), I achieved desired behavior. Camel route DSL is Something like
from("rest:get:tt:/{id}").to("rest:get:jjjj/llll/pppp/{id}?host=http://192.168.1.1:80")
But question still remains open that why it is not working with .toF().
Seems like you're using {id} syntax for http component uri, but I think it's only recognized by the rest component, so instead of having:
from("rest:get:tt:/{id}")
.toF("%s/%s?bridgeEndpoint=true", "http://192.168.1.1:80", "jjjj/llll/pppp/{id}");
you could try using dynamic endpoint .toD() with simple expression ${header.id}:
from("rest:get:tt:/{id}")
.toD("http://192.168.1.1:80/jjjj/llll/pppp/${header.id}?bridgeEndpoint=true");
Not exactly sure if that's what you're aiming for though

pollEnrich with dynamic URI and its number of executions

I want to listen on ActiveMQ topic based on the hostname of system and some other logic. I planned to use pollEnrich for it so I evaluate my logic and provide topic name in pollEnrich but as per document:
pollEnrich or enrich 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 i can figure out this
from("timer://ipc?repeatCount=1")
.. some logic..
.setHeader("topic_no",simple("{{env:HOSTNAME}}"))
.pollEnrich("mqtt:foo?host=tcp://0.0.0.0:1883&subscribeTopicNames=${header.topic_no}/status&clientId=ipc")
.to("log:my?showAll=true&multiline=true");
Please don't suggest to use hostname directly in URI. As I highlighted I have to compute other logic too.
What other option or way I can use?
Will pollEnrich kept listening on topic or it will listen once and end the route?
Update1:
I figured out we can use simple expression with for dynamic URI, But one issue with pollEnrich it only pick one message how i can make sure it kept on listening as consumer? I want that before pollEnrich part get execute once and TopicListener kept listening till application is up.
Will pollEnrich kept listening on topic or it will listen once and end the route?
Same as the fact you have figure out, Camel pollEnrich component will listen on topic and consume at most one message per call.
What other option or way I can use?
Repeat pollEnrich by loop
Create new route at run-time by routeBuilder
Option 1 is naive, but simple in concept. pollEnrich will do once and loop will repeat it. However, this method need to handle more scenario than you might expected.
Option 2 is a better approach. You create a route at run-time and the consumer endpoint URI is pass by variable. That said, you can create the consumer route dynamically after your computation logic.
Example for routeBuilder

For Apache Camel, is it possible to have half of a route synchronous and the second half async?

I currently have a camel route that exposes a cxf endpoint. When a messages comes through the endpoint I would first enrich that message with some information from another webservice and then do more processing afterwards. However, I want make the first half of this route synchronous so I can send back a response to whomever called my exposed cxf endpoint.
The route looks something like this:
from(cxf:CxfEndpoint)
.process(someProcessing)
.to(cxf:ExternalCxfEndpoint)
.to(activemq:queue:somequeue)
//return a response back to caller here
from(activemq:queue:somequeue)
... //additional processing here
...
The reason for this is because when a message comes via my exposed cxf endpoint I don't know if it's a valid message. I need to first validate it with the message enrichment. Once the message is enriched, I want let whomever sent the message know that their message is accepted but don't want them to wait for the message to make it through the whole route as that could take hours.
Does anyone know how this would work?
Thanks in advance!
I believe all you need to do is set exchangePattern to InOnly a.k.a. make it an Event Message. This should have your route not wait for a reply from ActiveMQ. Camel exchange will default to InOut when it's originating from a web service, as in your case.
A related question with an answer from a Camel dev here.
Also see this one for some details on the behavior when your broker is down.
Yes definitely , 100% possible. A simple example would be this :
From cxf endpoint
Store your request in a camel property or header
To xslt - generate xslt for cxf endpoint - Synchronous flow
Reset your original payload using set body.
Wiretap Endpoint - to any endpoint downstream or even a route , this becomes asynchronous . This won't take part in the above sync response .
Note- step 2 & 4 may not be required, it depends on your use case .
There are whole lots of things you can do, I just gave a very simple example . It doesn't need to be wiretap as well, but wiretap helps us not to write any additional custom exceptional handling.

Is there a way to force the Apache Camel http4 producer to stream instead of use chunked encoding?

I need to call a web service that requires streaming and I'd like to use the Camel http4 endpoint, however I can't seem to get it to stop using chunked encoding. Is there a way to either force streaming or turn off chunking?
I believe something like this may force http4 to stream your data:
exchange.getIn().setHeader(Exchange.CONTENT_ENCODING, "gzip");
You can find more details on the complete example: https://svn.apache.org/repos/asf/camel/trunk/components/camel-http4/src/test/java/org/apache/camel/component/http4/HttpCompressionTest.java
I think you need to enable stream cache. See this:
https://camel.apache.org/manual/latest/stream-caching.html

apache camel request response and how to route to next transformer

The concept of routing is nice in theory but in practice, I am a bit confused. I have a CXF method in my webservice
public Response someMethod(Request r) {
}
what I don't get is I need to route the Request to some further node so am I really supposed to do that in the java code or will camel generate an interface(asynch hopefully) that I can wire that node up to some transformer to a next node validator to some store and forward, etc and then finally have the store and forward reply with a Response that is somehow sent out the socket the Request came in from originally.
In the above method, I am forced to return the response back to the client in that method, right?
If I am supposed to put the code in the webservices method, is there some camel context I am supposed to call into?
Also, I want the "RAW" parameters of the SOAP method call and don't want to deal with SOAP Header and then also need to expose some REST apis as well that just accept a String.
EDIT: The proxy example from the answer below is the closest I have seen but even that one if I want to short cut and not even call the real webservice at an earlier node in the pipeline, I can't. I seem to have to call the end webservice code which is not wanted as we don't have any webservice code. We are trying to run it through existing pojos from a webservice call. If the validation node fails, we want to return a response, if it succeeds we want to forward the request on to another node where if that node fails we return a response or if it succeeds we want to forward the request on. There seems to be nothing for this??? Also, this seems like a pretty typical case to me so I am surprised or I am not getting something with all these ESB frameworks(mule, camel so far).
thanks,
Dean
Look at this official Example, it'll show how to do this
Or this Cxf proxy example if you want the RAW request
If you are in a Spring MVC webapp already - you could perhaps do this a bit easier with Spring WS and Jaxb. But that is a matter of taste. Example code here
never solved, we dropped camel as it is quite a pain compared to rolling your own.

Resources