I'm creating a RouteBuilder for a test:
final RouteBuilder routeBuilder = new RouteBuilder() {
#Override
public void configure() throws Exception {
from(start).routeId(id).
process(myProcessor).
to(end);
}
};
camelContext.addRoutes(routeBuilder);
and I need to also set some headers coming from a Map<String, String>. In other words I'd like to do something like:
headers.entrySet().
forEach(header -> {
setHeader(header.getKey(), constant(header.getValue()));
});
but that setHeader should be related to the RouteDefinition that I was creating inside the #configure method of the RouteBuilder.
How can I do it?
Thanks
Typing from my mobile. Thus format may not be correct:
final RouteBuilder routeBuilder = new RouteBuilder() {
#Override
public void configure() throws Exception {
RouteDefinition route = from(start).routeId(id);
headers.entrySet().
forEach(header -> {
route = route.setHeader(header.getKey(),
constant(header.getValue()));
});
route.process(myProcessor).
to(end);
}
};
camelContext.addRoutes(routeBuilder);`
Related
I saw in another post how manually adding the camel context and starting it should work, but it hasn't for me. I double checked the from, and to paths and they seem to be correct. Not sure why it's not calling the method and would appreciate some advice
public class CsvRouteBuilder extends DdsRouteBuilder {
private CsvConverterProcessor csvConverterProcessor;
private CamelContext camelContext;
#Autowired
public CsvRouteBuilder(CsvConverterProcessor csvConverterProcessor) throws Exception {
this.csvConverterProcessor = csvConverterProcessor;
camelContext.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("{{input.files.csv}}")
.routeId("CSVConverter")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("hitting");
}
})
.to("{{output.files.csv}}");
}
});
camelContext.start();
}
The processor is not called simply because your route is not properly declared such that Spring Boot is not aware of it.
The proper way is to make your class extend RouteBuilder to define your route(s) and annotate your class with #Component to mark it as candidate for auto-detection when using annotation-based configuration and classpath scanning.
Your code should rather be something like this:
#Component
public class CsvRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("{{input.files.csv}}")
.routeId("CSVConverter")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("hitting");
}
})
.to("{{output.files.csv}}");
}
}
I'm new to camel.
When I get the request to the endpoint, the camel flow should be started. RequestBody is the input to the flow (InputA).
Please let me know how to start this:
InputA -> ProcessA -> OutputA
OutputA -> ProcessB -> OutputB
OutputB -> ProcessC -> OutputC
Just as an example:
public class ProcessA{
public String methodA(String arg){
return arg;
}
}
public class ProcessB{
public String methodB(String arg){
return arg;
}
}
public class ProcessC{
public String methodC(String arg){
return arg;
}
}
How to flow the input and output using Camel data flow.
Any help or links will be appreciated.
I advice you to read the book Camel in action. There are a lot of examples, source code is also awailable. When i started to study camel, I found this book very useful.
Also In addition to Cluas answer i can add an example:
public class Example
{
public static void main(String[] args) throws Exception
{
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder()
{
#Override
public void configure() throws Exception
{
from("InputA").process(exchange -> {
//This is process A.
}).to("OutputA");
from("OutputA").process(exchange -> {
//This is process B.
}).to("OutputB");
from("OutputB").process(exchange -> {
//This is process C.
}).to("OutputC");
}
});
context.start();
//let camel complite his job
Thread.sleep(2000);
context.stop();
}
}
You can build 3 Camel routes, and then use some queue component to separate them, such as the internal direct (no queue by direct method invocation) or seda queues.
Pseudo routes would be something like:
from("someInput").process(...).to("seda:a")
from("seda:a").process(...).to("seda:b");
from("seda:b").process(...).to("seda:c");
Let's say you read the Json from a file and you want to process it inside a processor. Something like this:
from("file:/C:/TEST/")
.process(new MyProcessor())
.to("direct:anotherRouter");
MyProcessor class is a special kind of class that implements Processor. You need to override the process method.
public class MyProcessor implements Processor{
#Override
public void process(Exchange exchange) throws Exception {
}
}
In a camel route, the data is in the body. To get the data in a processor you should get it from the body. In the example, it is something like this
public class MyProcessor implements Processor{
#Override
public void process(Exchange exchange) throws Exception {
String data = exchange.getIn().getBody(String.class);
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(data);
//TODO: All the stuff you want to do with the data.
}
}
I am trying to create a unit test for the routing.
I have the following route configuration
from ("direct:getA")
.routeId("get-a").startupOrder(1)
.process(exchange -> {
QueryObject queryObject = exchange.getIn().getBody(QueryObject.class);
exchange.getIn().setHeader(foo, queryObject.getH());
exchange.setOut(exchange.getIn());
})
.choice()
.when(header(foo).isEqualTo(fooConstant.bar))
.process("barProcessor")
.when(header(foo).isEqualTo(fooConstant.bie))
.process("bieProcessor")
.end();
My question is, how can I mock "barProcessor" and "bieProcessor"?
I tried to use adviceWith but I could not retrieve the routeDefinition. The context.getRouteDefinitions() returns an empty list.
Edit:
Below is the code snippet from my test.
RouteDefinition routeDef = context.getRouteDefinition("get-a");
routeDef.adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
interceptSendToEndpoint("*barProcessor*").process(
new Processor() {
#Override
public void process(Exchange exchange) {
System.out.println("bar");
}
}
);
interceptSendToEndpoint("*bieProcessor*").process(
new Processor() {
#Override
public void process(Exchange exchange) {
System.out.println("Bie");
}
}
);
}
});
String request = <JSON Request>;
websocket.sendTest(request);
But the context.getRouteDefinition("get-a"); is returning null. And when I also used context.getRouteDefinitions(), it returns an empty list.
I found the cause of this issue.
I forgot to Override the createRouteBuilder and createJndiContext.
#Override
protected RouteBuilder createRouteBuilder() {
return new SampleRoute(<param>);
}
#Override
protected JndiContext createJndiContext() throws Exception {
JndiContext context = new JndiContext();
context.bind("barProcessor", new BarProcessor());
context.bind("bieProcessor", new BieProcessor());
return context;
}
I found the solution from this link: Unit Test
I followed guide here, and I was successfully able to configure a producer on my bean endpoint like this:
#Produce( uri = "activemq:foo" )
private MyListener myListener;
MyListener is:
public interface MyListener {
#InOnly
public void send( String message );
}
and my bean:
public class MyBeanEndpoint {
#Produce( uri = "activemq:foo" )
private MyListener myListener;
#Handler
public void doSomething( final Object body ) {
...
}
public void setMyListener( final MyListener myListener ) {
this.myListener = myListener;
}
Now, how can I test this?
I mean: my test extends CamelTestSupport and I configured my routes with
#Override
public RouteBuilder createRouteBuilder() {
return new RouteBuilder() { ... }
That is: I've reproduced camel context, but I've NO spring context configured and I want (if possible) to avoid instantiating it.
How can I mock producer or make Camel instantiate and inject this bean into my bean endpoint?
What is the best way to test such situation using Apache Camel features like CamelTestSupport and similar utilities?
My reference test is:
public class Test extends CamelTestSupport {
private static BeanEndpoint beanEndpoint
#BeforeClass
public static void init() {
beanEndpoint.setActivemqMyListener( ??? );
}
#Override
public CamelContext createCamelContext() {
context = new DefaultCamelContext();
context.addComponent( "activemq", new SedaComponent() );
return context;
}
#Override
public RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from( "activemq:foo" )
.to( "mock:out" );
}
};
}
#Test
public void testFooQueue() throws Exception {}
Let Camel create your bean, then the various dependency injection and whatnot is configured for you.
private static BeanEndpoint beanEndpoint
...
beanEndpoint = camelContext.getInjector().newInstance(BeanEndpoint.class);
I want to test multiple camel RouteBuilder in a single unit test
what I have:
Custom camel processor that changes state
public class MyProcessor implements Processor {
MyState state;
public MyProcessor(MyState state) {this.state = state;}
#Override
public void process(Exchange exchange) throws Exception {
state.setState(state.getState() + 5);
}}
Two simple RouteBuilders: first routes messages from "direct:start" to "direct:endroute1" second pick up messages from "direct:endroute1" and routes somewhere "mock:endroute2"
public class MyRouteBuilder1 extends RouteBuilder {
MyState state;
public MyRouteBuilder1(MyState state) {this.state = state;}
#Override
public void configure() throws Exception {
from("direct:start").process(new MyProcessor(state)).to("direct:endroute1");
}}
public class MyRouteBuilder2 extends RouteBuilder {
MyState state;
public MyRouteBuilder2(MyState state) {this.state = state;}
#Override
public void configure() throws Exception {
from("direct:endroute1").process(new MyProcessor(state)).to("mock:endroute2");
}}
Writing unit test for a single route builder is straightforward:
public class MyTest extends CamelTestSupport {
MyState state = new MyStateImpl();
#EndpointInject(uri = "mock:result")
protected MockEndpoint resultEndpoint;
#Test
public void testSingleRoute() throws Exception {
resultEndpoint.expectedMessageCount(1);
template.sendBody("direct:start", new Object());
assertTrue(state.getState() == 5);
resultEndpoint.assertIsSatisfied();
}
#Override
protected RouteBuilder createRouteBuilder() {
return new MyRouteBuilder1(state) {
public void configure() throws Exception{
super.configure();
from("direct:endroute1").to("mock:result");
}
};
}
}
What I really want to do is somehow to override CamelTestSupport.createRouteBuilder that will test whole chain of message processing from direct:start to mock:endroute2. As a result state.getState() should be 10
Try to override method:
protected RouteBuilder[] createRouteBuilders() {...}
from CamelTestSupport. It's available since version 2.17
you can just add multiple RouteBuilders to the context using the context.addRoutes(RouteBuilder) API
see this unit test for an example:
https://svn.apache.org/repos/asf/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/AddRoutesAtRuntimeTest.java
You could use one RouteBuilder including the routes of multiple other RouteBuilders.