Produce Long Kafka Header with Apache Camel - java

In my Springboot Camel application I'm using the Kafka integration to produce message on a topic.
I compared message produced by Camel Kafka integration with message produced by Kafka Spring integration and I noticed one little difference:
in OffsetExplorer, messages produced by Spring Kafka uses an Header "spring_json_header_types" with the class of all other headers, and header Long or Integer are correctly showed and serialized.
With Camel instead, if I set an header not String, in OffsetExplorer it is represented with the square char.
I did my research and found that Spring Kafka uses the DefaultKafkaHeaderMapper to create this header, and this help the inbound process to know how to deserialize the other header.
How can I use it in my Camel Kafka Producer?
Here my code:
#Component
public class KafkaProducerRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("timer:myTimer?period=10000")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
Map<String, Object> headers = new HashMap<>();
headers.put("TIMER_COUNTER_1", exchange.getProperty(Exchange.TIMER_COUNTER, Long.class));
headers.put("TIMER_COUNTER_2", String.valueOf(exchange.getProperty(Exchange.TIMER_COUNTER, Long.class)));
exchange.getIn().setHeaders(headers);
}
})
.to("kafka:topic1?brokers=localhost:9092");
}
}

Related

Translating from WSO2 to camel with Java DSL: How to forward with URI pattern

I'm removing WSO2 from our stack and I have to write in Camel Java DSL the endpoints that were implemented in WSO2.
In WSO2 we had an endpoint as below:
<resource methods="OPTIONS GET" uri-template="/request/{data}" inSequence="requestreset"/>
<http method="GET" uri-template="http://127.0.0.1/index.php?_q=requestreset&data={uri.var.data}"/>
My code in Java Camel's Router is:
public class DefaultRouteBuilder extends RouteBuilder {
private HashMap<String, String> routeCorresponding = new HashMap();
#Override
public void configure() throws Exception {
routeCorresponding.put("reset/request/{data}", "http://127.0.0.1/index.php?_q=requestreset&data={data}");
for (Map.Entry<String, String> pair : routeCorresponding.entrySet()) {
String url = pair.getKey();
String target = pair.getValue();
String resultTarget = target.contains("?") ? target + "&bridgeEndpoint=true" : target + "?bridgeEndpoint=true";
fromF("servlet:"+ url +"?matchOnUriPrefix=true")
.log("Request: ${in.header."+ Exchange.HTTP_METHOD +"} to ${in.header."+ Exchange.HTTP_URI +"}")
.toF(resultTarget);
}
}
}
But it doesn't work as I would want it because when I make a request to tomcat.myserver.com:8080/camel-example-servlet/reset/request/blablablablabla I get a response this:
org.apache.camel.http.common.HttpOperationFailedException: HTTP operation failed invoking http://127.0.0.1/index.php/reset/request/blablablablabla?_q=requestreset&data=%7Bdata%7D with statusCode: 404
Instead of http://127.0.0.1/index.php/reset/request/blablablablabla?_q=requestreset&data=%7Bdata%7D, I would like the following request to be on http://127.0.0.1/index.php?_q=requestreset&data=blablablablabla
Is it possible to achieve in Camel/Java DSL that? Basically what WSO2 was implementing with the URI template and the curly brackets around fields?
You can absolutely achieve that - but your {data} block is stored as a header, so you need to refer to it as ${header.data} in your target URI.
Here's an example using the REST DSL:
restConfiguration().component("servlet");
rest("/reset/request/{data}")
.get()
.route()
.log("Received request...")
.setHeader(Exchange.HTTP_PATH, simple("/index.php"))
.setHeader(Exchange.HTTP_QUERY, simple("_q=requestreset&data=${header.data}"))
.to("http://localhost:8080?bridgeEndpoint=true");
Edit based on your question below. Alternatively, if you need to proxy hundreds of URLs, instead of creating hundreds of routes, you could just create one single route which proxies them all and implement your routing logic in a Processor, e.g.:
from("servlet:?matchOnUriPrefix=true")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
// set your target URI here, look it up from the HashMap, etc.
}
})
.to("http://localhost:8080?bridgeEndpoint=true");

Sending Camel HTTP Post custom body

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.

Camel: how to route data from process method to another pipeline?

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

camel route http response xml parsing

I am new to using camel and I need to build a route in JAVA to process some xml returned by http request. I tried to parse the body of the response by setting up a route with a processor and log it to a file setting the consumer as http url but it didn't work. Then I tried to set up a jms queue to grab and process it from the queue with similar result.
I think I am getting the 200 response but the producer text file I set it to write to is not working and the log4j in DEBUG is not too informative on isolating the issue. Does anyone have any insight on this issue to point me in the right camel direction? thanks in advance!
public static void main(String[] args) throws Exception {
CamelContext camelContext = new DefaultCamelContext();
// connect to embedded ActiveMQ JMS broker
ConnectionFactory connectionFactory =
new ActiveMQConnectionFactory("vm://localhost");
camelContext.addComponent("jms",
JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
try {
camelContext.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:start")
.to("http://tomcatappurl:8080/format=xml?bridgeEndpoint=true")
.process(new OrderProcessor())
.to("log:DEBUG?showBody=true&showHeaders=true")
.log("file:C:/Desktop/camellog1.txt")
.to("log:DEBUG?showBody=true&showHeaders=true")
.log("${headers}")
.convertBodyTo(String.class)
.to("file:C:/Desktop/camellog1.txt")
.log("${in.headers}")
.to("stream:out")
.to("jms");
from("jms:incomingOrders")
.process(new Processor() {
public void process (Exchange exchange) throws Exception {
//HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
System.out.println("Response received from Google, is streamCaching = " + exchange.getContext().isStreamCaching());
System.out.println("----------------------------------------------IN MESSAGE--------------------------------------------------------------");
System.out.println(exchange.getIn().getBody(String.class));
System.out.println("----------------------------------------------OUT MESSAGE--------------------------------------------------------------");
//System.out.println(exchange.getOut().getBody(String.class)); //Activating this line causes empty response on browser
}
})
.to("file:C:/Users/Desktop/camellog1.txt?fileExist=Append");
}
});
camelContext.start();
} finally {
camelContext.stop();
}
}
I think your routes are not running.
You need something (like a timer) to trigger your routes, for example:
from("timer:myTimer?period=30s")
.to("direct:start");
Camel documentation for Direct component says:
The direct: component provides direct, synchronous invocation of any consumers when a producer sends a message exchange.
So you need something else to start the invocation of the route.
Mind that your first route must finish to the correct JMS queue:
// ... cut
.to("file:C:/Desktop/camellog1.txt")
.log("${in.headers}")
.to("stream:out")
.to("jms:incomingOrders");
without the queue name it will not work.

Apache Camel, SOAP/CXF client request exchange error

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 ?

Categories

Resources