I use Apache Camel’s Spring Main to boot my Camel application. I need my application to read the command line arguments to set some parameters. So, I cannot use property files.
At the moment, I can pass arguments via the JVM system properties, and it works well:
Application.java
public class Application extends org.apache.camel.spring.Main {
public static void main(String[] args) throws Exception {
Application app = new Application();
instance = app;
app.run(args);
}
}
camel-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="shutdownBean" class="com.example.ShutdownBean" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="file:{{inputFile}}?noop=true"/>
<to uri="bean:shutdownBean" />
</route>
</camelContext>
</beans>
I run the app with java com.example.Application -DinputFile=C:/absolute/path/to/watch and everything works fine:
…
FileEndpoint INFO Using default memory based idempotent repository with cache max size: 1000
InternalRouteStartupManager INFO Route: route1 started and consuming from: file://C:/absolute/path/to/watch
AbstractCamelContext INFO Total 1 routes, of which 1 are started
…
But I would like to have some input validation and make the app easier to use because -D could be confusing for a non Java user. So I change Application.java:
public class Application extends org.apache.camel.spring.Main {
private File inputFile;
public static void main(String[] args) throws Exception {
Application app = new Application();
instance = app;
app.run(args);
}
public Application() {
addOption(new ParameterOption("i", "inputFile", "The input file", "inputFile") {
#Override
protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) {
File file = FileUtils.getFile(parameter);
// some business validation
setInputFile(file);
}
});
}
private void setInputFile(File inputFile) {
this.inputFile = inputFile;
}
}
Then, I could use the following command to run the application: java com.example.Application -inputFile C:/absolute/path/to/watch
How can I use my inputFile field into my Camel route?
Call addProperty(String key, String value) in your doProcess method. Then it will be accessible throught {{key}} notation.
MyApplication:
public final class MyApplication extends Main {
private MyApplication() {
super();
addCliOption("g", "greeting", "Greeting");
addCliOption("n", "name", "Who to greet");
}
public static void main(String[] args) throws Exception {
MyApplication app = new MyApplication();
app.configure().addRoutesBuilder(MyRouteBuilder.class);
app.run(args);
}
private void addCliOption(String abbrevation, String parameterName, String description) {
addOption(new ParameterOption(abbrevation, parameterName, description, parameterName) {
protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) {
addProperty("console." + parameterName, parameter);
}
});
}
}
MyRouteBuilder:
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("quartz:foo")
.log("{{console.greeting}} {{console.name}}");
}
}
java org.apache.camel.example.MyApplication -greeting Hello -name Morgan
23:10:25.862 [DefaultQuartzScheduler-MyCoolCamel_Worker-1] INFO route1 - Hello Morgan
23:10:26.832 [DefaultQuartzScheduler-MyCoolCamel_Worker-2] INFO route1 - Hello Morgan
23:10:27.829 [DefaultQuartzScheduler-MyCoolCamel_Worker-3] INFO route1 - Hello Morgan
Related
Available examples of the usage of the Camel Test component show how to test the expectations of a route:
However what I need to do is mock the body (manually setting it) of an intermediate route, e.g.:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="exampleBean" class="xxx.ExampleBean"/>
<routeContext id="routesTest" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:route1" />
<to uri="direct:route2" />
<log message="${body}"/>
</route>
<route>
<from uri="direct:route2"/>
<to uri="bean:exampleBean"/>
<to uri="direct:route3" />
</route>
<route>
<from uri="direct:route3"/>
<log message="${body}"/>
</route>
</routeContext>
</beans>
In this scenario I want to completely avoid the actual execution of bean:exampleBean, mocking the result of its execution.
My test class:
public class MyTests extends CamelSpringTestSupport {
#Produce(uri = "direct:route1")
protected ProducerTemplate inputProducerTemplate;
#EndpointInject(uri = "mock:bean:exampleBean")
protected MockEndpoint mockBeanExampleBean;
#Test
public void testRoute() throws Exception {
CompletableFuture<Object> future = inputProducerTemplate.asyncSendBody("direct:route1", "Some message");
Object o = future.get();
}
#Override
public String isMockEndpoints() {
return "bean:exampleBean";
}
#Override
protected AbstractApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("spring/gesti-test-application-context.xml");
}
}
public class ExampleBean {
public String enhance(String message) {
System.out.println(message);
//Here I would call a REST API
return "MY API RESULT";
}
}
When using mockBeanExampleBean.whenAnyExchangeReceived(exchange -> exchange.getMessage().setBody("My message")); it allows to override the input to exampleBean, but doesn't avoid its execution.
In the context of your unit test, route2 might be a "mock" component instead. A clean way of achieving that is to declare the route(s) in the properties file. The legibility of the routes gets harder, though.
Then, you could:
#EndpointInject("mock://route2")
MockEndpoint mockSecondStep;
mockSecondStep.whenExchangeReceived(1, e -> {
List whatever = new ArrayList<>();
e.getMessage().setBody(whatever);
});
I solved it using an InterceptStrategy:
public class MyTests extends CamelSpringTestSupport {
#Test
public void testRoute() throws Exception {
CompletableFuture<Object> future = template.asyncSendBody("direct:route1", "Some message");
Object o = future.get();
assertEquals("INTERCEPTED!", o);
}
#Override
protected AbstractApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("spring/gesti-test-application-context.xml");
}
#Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() {
context.getProcessorDefinition("bean:exampleBean").addInterceptStrategy(
(context, definition, target, nextTarget) -> exchange -> exchange.getOut().setBody("INTERCEPTED!"));
}
};
}
}
public class ExampleBean {
public String enhance(String message) {
System.out.println(message);
//Here I would call a REST API
return "MY API RESULT";
}
}
I'm new to Apache Camel. I have written simple program to place a file to another Location using camel routes. And I have written Junit and Mock Tests for that.
This is my simpleCamelRoute.java
#Component
public class SimpleCamelRoute extends RouteBuilder {
#Autowired
Environment environment;
#Override
public void configure() throws Exception {
from("{{startRoute}}").log("Timer Invoked and the body" + environment.getProperty("message"))
.pollEnrich("{{fromRoute}}").to("{{toRoute1}}");
}
}
this is SimpleCamelRouteTest.java
#ActiveProfiles("dev")
#RunWith(CamelSpringBootRunner.class)
#DirtiesContext(classMode =
DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
#SpringBootTest
public class SimpleCamelRouteTest {
#Autowired
ProducerTemplate producerTemplate;
#Autowired
Environment environment;
#BeforeClass
public static void startCleanUp() throws IOException {
FileUtils.cleanDirectory(new File("data/input"));
FileUtils.deleteDirectory(new File("data/output"));
}
#Test
public void testMoveFile() throws InterruptedException {
String message = "type,sku#,itemdescription,price\n" + "ADD,100,Samsung TV,500\n" + "ADD,101,LG TV,500";
String fileName = "fileTest.txt";
producerTemplate.sendBodyAndHeader(environment.getProperty("fromRoute"), message, Exchange.FILE_NAME, fileName);
Thread.sleep(3000);
File outFile = new File("data/output/" + fileName);
// File outFile = new File("data/output/"+"abc.txt");
assertTrue(outFile.exists());
}
}
this is my application.yml file
spring:
profiles:
active: dev
---
spring:
profiles: mock
startRoute: direct:input
fromRoute : file:data/input?delete=true&readLock=none
toRoute1: mock:output
message: MOCK Environment
---
spring:
profiles: dev
startRoute: timer:hello?period=10s
fromRoute : file:data/input?delete=true&readLock=none
toRoute1: file:data/output
message: DEV Environment
---
Like the same way I tried with Mock Test through MockEndPoints.
I have Gone through Apache Camel official site: https://camel.apache.org/cdi-testing.html but I didn't understand the flow to test through Camel Arquillian Integration test.
How can I test my project through Arquillian.
I am using Solr + Spring Data Solr for Solr Indexing.
I am getting following error when I am trying save the solr document.
HTTP Status 500 - Request processing failed; nested exception is org.springframework.data.solr.UncategorizedSolrException: Expected mime type application/octet-stream but got text/html.
Here is my code:
Config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="http://www.springframework.org/schema/data/solr http://www.springframework.org/schema/data/solr/spring-solr.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<solr:repositories base-package="my.solr.repo"
multicore-support="true" />
<solr:solr-server id="solrServer" url="http://localhost:8983/solr" />
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg index="0" ref="solrServer" />
</bean>
</beans>
#Repository
public class SolrMyRepository extends
SimpleSolrRepository<SolrmyModel, Serializable> {
#Autowired
public SolrMyRepository(final SolrTemplate solrTemplate) {
super(solrTemplate);
}
}
#SolrDocument(solrCoreName = "my")
public class SolrMyModel {
#Id
#Indexed
private Long id;
#Indexed
private String myTitle;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMyTitle() {
return myTitle;
}
public void setMyTitle(String myTitle) {
this.myTitle = myTitle;
}
}
#Service
public class SolrMyService {
#Autowired
private SolrMyRepository solrMyRepository;
public void test() {
final SolrMyModel model = new SolrMyModel();
model.setId((long) 1);
model.setTitle("My title");
System.out.println(model);
solrMyRepository.save(model);
}
}
I am not sure what else I am missing but constantly I am getting this error.
Solution:
I got over the above problem as I have not create a solr core by running following command.
./solr create -c my
As now its working, how can I created core programatically?
I got over the above problem as I have not create a solr core by running following command.
./solr create -c my
my problem is, I don't know how I can access exchange's header values inside a string-template declaration. I would like to have internationalized mail templates. The test code below ...
public class StringTemplateTest extends CamelTestSupport {
#EndpointInject(uri = "mock:result")
protected MockEndpoint resultEndpoint;
#Produce(uri = "direct:start")
protected ProducerTemplate template;
#Test
public void testTemplating() throws Exception {
resultEndpoint.expectedBodiesReceived("test");
template.sendBodyAndHeader("test", "lang", "de");
resultEndpoint.assertIsSatisfied();
}
#Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
public void configure() {
from("direct:start").to("string-template:mailTemplate_$simple{in.header.lang}.tm").to("mock:result");
}
};
}
}
ends in a ...
java.io.FileNotFoundException: Cannot find resource: mailTemplate_$simple{in.header.lang}.tm in classpath for URI: mailTemplate_$simple{in.header.lang}.tm
I would expect, the string-template is lookig for mailTemplate_de.tm.
Thank you for help in advance!
Your problem is that .to("component:xyz") endpoints are evaluated at the time the route is built - they are not dynamic and won't pick up ${} properties.
Instead you need to use recipientList, like this:
from("direct:start")
.recipientList(simple("string_template:mailTemplate_${in.header.lang}.tm"))
.to("mock:result")
I'm creating a application with Spring-jersey-camel. I wanted to expose my jersey layer and internally invoke camel routes to invoke resources.
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
applicationContext.xml
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
<packageScan>
<package>com.company.myapp.camel</package>
<excludes>**.*</excludes>
<includes>*Routes.java</includes>
</packageScan>
</camelContext>
MyRoutes.java
#Component
public final class MyRoutes extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:getOrdersData").validate(body().isNotNull())
.log("Camel to get orders")
.to("restlet:http://localhost:8081/ordersapp/rest/order/123");
}
}
OrderResourceImpl.java
#Component
#Path("/orderLookup")
public class ReservationResources {
#org.apache.camel.produce
ProducerTemplate producer;
public void setProducer(ProducerTemplate producer) throws Exception {
this.producer = producer;
}
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("{orderId}")
public Response orderLookup(#PathParam("orderId") final long orderrId){
Response r = Response.noContent().build();
//Producer is null. throws nullPointerException
String order= producer.requestBody("direct:getOrdersData", orderId, String.class);
r = Response.ok().entity(reservation).build();
return r;
}
}
Any idea what I'm doing wrong? or how to inject myRoute/ProducerTemplate im my orderResourceImpl.java. Thanks in advance
Two Options,
If ReservationResources is a spring bean then, Inject the Camel Context into it and create a ProducerTemplate from that
ProducerTemplate template = camelContext.createProducerTemplate();
If ReservationResources is not a spring bean then get the Camel Context via a static method https://stackoverflow.com/a/13633109/3696510 and then create the ProducerTemplate.
ProducerTemplate template = StaticSpringApplicationContext.getBean("camelContext").createProducerTemplate()
Also if you do use that StaticSpringApplicationContext mentioned in the link, I would add this method to it.
public static <T> T getBean(String beanName, Class<T> clazz) {
return (T) CONTEXT.getBean(beanName,clazz);
}