I am trying to save a value on the Camel Exchange between a Request - Response invocation against a QPID endpoint.
You can see from my code that I set a Header (and Property) before i invoke the Endpoint. Upon return the same Header and Property Values are null.
I basically want to keep a track of the fileName and filePath so that I can write the results into the same location
Really struggling with this.
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Value;
public class ProcessingRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
//#formatter:off
from("file:/home/molko/in/?recursive=true&include=.*.txt")
.log("File read from disk : ${file:name}")
.doTry()
.setHeader("JMSReplyTo", constant("response-1"; {create:always, node:{type:queue}}"))
.setHeader("JMSCorrelationID", constant(java.util.UUID.randomUUID().toString()))
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
final String fileParent = exchange.getIn().getHeader("CamelFileParent", String.class);
final String endPath = fileParent.substring(fileParent.lastIndexOf('/') + 1);
exchange.getIn().setHeader("endPath", endPath);
exchange.setProperty("endPath", endPath);
}
})
.to(amqp:request-1;{node:{type:queue}}?preserveMessageQos=true?exchangePattern=InOut")
.doCatch(Exception.class)
.log("Failed : ${file:name}")
.log("${exception.stacktrace}")
.stop();
from("amqp:response-1; {create:always, node:{type:queue}}")
.log("Received from qpid broker : ${date:now}")
.doTry()
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
byte[] response = exchange.getIn().getBody(byte[].class);
System.out.println("properties : " + exchange.getProperties());
System.out.println("headers : " + exchange.getIn().getHeaders());
}
})
.to("file:/home/molko/out")
.doCatch(Exception.class)
.log("Failed from qpid brokre : ${date:now}")
.log("${exception.stacktrace}")
.stop();
//#formatter:on
}
}
includeAllJMSXProperties is probably what you are looking for ,
Camel 2.11.2/2.12: Whether to include all JMSXxxx properties when
mapping from JMS to Camel Message. When set to true properties such as
JMSXAppID, and JMSXUserID etc will be included. Note: If you are using
a custom headerFilterStrategy then this option does not apply.
Source : https://camel.apache.org/jms.html
Related
I am new to Apache camel. I am trying to create routes to call multiple rest APIs and aggregate the response into one.
But for some reason, the JSON request that I am creating does not reach the rest endpoint.
During debug, I see that Exchange objects do have the values that I have set and get converted into byte array and on the other side, rest API recieves empty objects.
I am working on a Spring boot project and I have tried different ways of marshalling the request to JSON including Gson and Jackson. None of which seem to work.
Please assist.
from("direct:oneResponse")
.multicast(new MyAggregationStrategy()).parallelProcessing()
.to("direct:rest1call", "direct:rest2call")
.end();
from("direct:rest1call")
.routeId("rest1call")
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.setHeader("Content-Type", constant("application/json"))
.setHeader("Accept", constant("application/json"))
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getIn().setBody(<<valid json>>); //json values as required for the rest call.
}
})
.to("http4://localhost:5555/mock/rest1call")
.setProperty("route", simple("routeId"))
.unmarshal(new JacksonDataFormat(Rest1Response.class));
from("direct:rest2call")
.routeId("rest2call")
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.setHeader("Content-Type", constant("application/json"))
.setHeader("Accept", constant("application/json"))
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getIn().setBody(<<valid json>>); //json values as required for the rest call.
}
})
.to("http4://localhost:5555/mock/rest2call")
.setProperty("route", simple("routeId"))
.unmarshal(new JacksonDataFormat(Rest2Response.class));
Can you try to create a processor and specify all the headers and body in it?
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getOut().setHeader(Exchange.HTTP_METHOD, HttpMethod.POST);
exchange.getOut().setHeader(Exchange.CONTENT_TYPE, "application/json");
exchange.getOut().setHeader("Accept", "application/json");
/* this is one way, string representation of json, but maybe you can try to build Model and fill that model with data */
exchange.getIn().setBody(<<valid json>>); //json values as required for the rest call.
}
})
if you decide to go with models, use marshaling after processor just to be sure your data is converted to JSON.
.marshal(yourDataFormat)
Try GsonDataFormat it works pretty good for me.
I have code like this:
.from("file://" + FTP_FILES + "?idempotent=true")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
list = parseDataFromExchange(ecxhange);
}
I want to send this data to another pipeline vm:myEndpoint
I believe that Camel can this but google didn't help me.
How can I achieve this ?
Just use a ProducerTemplate from inside your Processor, then you can send any message to any Camel endpoint. You can find more information on the Camel website such as: http://camel.apache.org/producertemplate.html
I have route A that calls route B:
from("direct:a")
.to("direct:b");
from("direct:b")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception
{
System.out.println("Route B URI: " + exchange.getUnitOfWork().getRouteContext().getFrom().getEndpointUri()); //oops, prints direct:a
}
});
I would like the nested route B to print out its own URI, not the URI of the encapsulating route A. How could I do it?
Afaik, I don't think it's possible as is.
The UnitOfWorks keep a Stack of RouteContext, but this stack is not publicly accessible. However, you can access a history of the processor in which the exchange has been routed. This collection of MessageHistory is located in an header Exchange.MESSAGE_HISTORY. It contains the id of the processor and (sanitized) uri of the endpoints.
A more simple/robust approach can be to add explicitly a header on each route invoking the route B.
Personally, I don't think it's a good idea to depend on such information // internal details of the route!
Add a routeId() instruction to your route and use that to access your route definition:
from("direct:b")
.routeId("routeB")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("Route B URI: " + exchange.getContext().getRoute("routeb").getFrom().getEndpointUri());
}
});
I'm trying to build simple Camel route to public webservice,
http://wsf.cdyne.com/WeatherWS/Weather.asmx
I'm using latest Camel with Spring, CXF, SOAP and Java Config Modules.
Here's my CxfEndpoint :
#Bean(name = "testCxfBean")
public CxfEndpoint createTestEndpoint() throws ClassNotFoundException {
CxfEndpoint endpoint = new CxfEndpoint();
endpoint.setAddress("http://wsf.cdyne.com/WeatherWS/Weather.asmx");
endpoint.setWsdlURL("http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL");
endpoint.setEndpointNameString("WeatherSoap");
endpoint.setServiceNameString("Weather");
return endpoint;
}
And here is my route :
#Component
public class TestCXFRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
SoapJaxbDataFormat dataFormat = new SoapJaxbDataFormat("com.cdyne.ws.weatherws", new ServiceInterfaceStrategy(
WeatherSoap.class, true));
from("timer:testTimer?period=5000").process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getIn().setBody(new GetWeatherInformation());
}
}).setHeader("operationName", constant("GetWeatherInformation")).marshal(dataFormat)
.to("cxf:testCxfBean?serviceClass=com.cdyne.ws.weatherws.WeatherSoap").log("level:info");
}
}
What I'm trying to do here is query weather information every 5 seconds, using GetWeatherInformation operation, marshalling relevant object, and simply logging result.
However I'm getting such error :
Exchange[
Id ID-darkstar-dev-39021-1423838783518-0-4
ExchangePattern InOnly
Headers {breadcrumbId=ID-darkstar-dev-39021-1423838783518-0-3, CamelRedelivered=false, CamelRedeliveryCounter=0, firedTime=Fri Feb 13 15:46:31 CET 2015, operationName=GetWeatherInformation}
BodyType byte[]
Body <?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:Envelope xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns3="http://ws.cdyne.com/WeatherWS/"> <ns2:Body> <ns3:GetWeatherInformation/> </ns2:Body></ns2:Envelope>
]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
java.lang.IllegalArgumentException: Get the wrong parameter size to invoke the out service, Expect size 0, Parameter size 252. Please check if the message body matches the CXFEndpoint POJO Dataformat request.
What am I doing wrong ?
I have a Camel route with an onCompletion() which then hits a Processor. Within this processor it gets a header from the Exchange but this header comes back null.
I know that onCompletion() runs at the end of that particular route but surely the Exchange headers should still be valid and usable. inputLocation below is defined higher up in the class and works for previous routes.
from("file://"+inputLocation+"?initialDelay=5000&delay=2000&recursive=true&delete=true")
.onCompletion()
.process(storedProcProcessor())
.end()
.choice()
.when(appContext.getBean(AppPredicate.class))
.log("Need to check against APP in the database for destination.")
.setHeader(AppConstants.INPUTLOCATION, simple(inputLocation))
.process(databaseProcessor())
.endChoice();
I checked with:
#Override
public void configure() {
from("direct:start")
.onCompletion()
.process(new Processor() {
#Override
public void process(final Exchange exchange) throws Exception {
LOG.info("Hello, {}", exchange.getIn().getHeader("myHeader"));
}
})
.end()
.setHeader("myHeader").constant("World!");
}
}
This prints
Hello, World!
Thus, the header myHeader is still available in onCompletion. So, I guess that your header is never properly set?