Camel first experience - apache-camel

I'm very new with Apache Camel. I can't get the simplest Camel example working. Here is the code:
public class CamelFE {
public static void main(String[] args) {
CamelContext cc = new DefaultCamelContext();
cc.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
System.out.println("Go!");
from("file://Users/Foo/Desktop/IN")
.to("file://Users/Foo/Desktop/OUT");
});
}
cc.start();
cc.stop();
}
Both directories exists, in the from one there is one simple file, helo.txt. The route starts and Go! message is displayed but no file was moved to the to directory. What am I missing?
Edit:
this is the console output.
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4j: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details
Go!

I'm guessing you're using Windows, since you have references to Users/.../Desktop. If that's the case, your file syntax is slightly off. Rather than file://Users/Foo/Desktop, you should have file:///Users/Foo/Desktop.
You also need to allow enough time for the processing to occur before the application terminates. You might add a Thread.sleep. Note that in a web application, this wouldn't be an issue as the app stays running.
public class CamelFE {
public static void main(String[] args) throws Exception {
CamelContext cc = new DefaultCamelContext();
cc.addRoutes(new RouteBuilder()
{
#Override
public void configure() throws Exception {
System.out.println("Go!");
from("file:///Users/Foo/Desktop/IN").to("file:///Users/Foo/Desktop/OUT");
}
});
cc.start();
Thread.sleep(10000);
cc.stop();
}
}

Related

Camel - Passing specific parameters from routes to processor

I'm trying to setup a route that process files, here is my route configuration:
#Component
public class MyRoute extends RouteBuilder {
public static final String FIRST_ROUTE = "firstRoute";
public static final String SECOND_ROUTE = "secondRoute";
private final Processor myProcessor;
#Autowired
public MyRoute (#Qualifier("my.processor") Processor myProcessor) {
this.myProcessor= myProcessor;
}
#Override
public void configure() throws Exception {
from("file://{{data.input.dir}}?moveFailed=errors&delete=true&doneFileName=ACK-${file:name}&include=MY-FILE-FIRST.*")
.routeId(FIRST_ROUTE)
.process(myProcessor);
from("file://{{data.input.dir}}?moveFailed=errors&delete=true&doneFileName=ACK-${file:name}&include=MY-FILE-SECOND.*")
.routeId(SECOND_ROUTE)
.process(myProcessor);
}
}
As you can see I have two route for two files that have different name (one with FIRST, one with SECOND).
I want to trigger the process with variable to avoid to check the filename inside the process.
Currently my process function look like that:
public void process(Exchange exchange) throws Exception
What I want is something like that:
public void process(Exchange exchange, String identifier) throws Exception
And have the identifier set in the route definition (it's static, not depending on the filename, I need to have "FIRST" for the first route, and "SECOND" for the second one).
Is this possible ?
Because a process interface signature only takes an Exchange parameter, we cannot do process(Exchange exchange, String identifier).
Instead we can create a bean and call the method from the route like below.
from("file://{{data.input.dir}}?moveFailed=errors&delete=true&doneFileName=ACK-${file:name}&include=MY-FILE-SECOND.*")
.routeId(SECOND_ROUTE)
.bean(myBean,"process(*, " + SECOND + ")");

Camel standalone - configuration of PropertiesComponent does not work on #BeanInject'ed beans

Note: Question is about standalone (using Main class) behaviour of the unreleased Camel 3.0.0-M2 version which has many enhancements for standalone mode over Camel 2.x - the code below is not intended to work on Camel 2.x
Problem: I noticed that modifications on the properties component as described in [1] do not affect config properties injected into beans. In my case I want to set the pc's environmentVariableMode to override (fallback is the default).
While the override was effective on the route, the bean got injected with the original property value.
The property "hi" in application.properties is set to "Hello" and the environment variable "hi" is set to "Huhu" which should override the former when environmentVariableMode is set to override (2).
When run:
System env var hi=Huhu
14:34:02.282 [Camel (camel-1) thread #2 - timer://foo] INFO route1 - Huhu from route
14:34:02.297 [Camel (camel-1) thread #2 - timer://foo] INFO route1 - Hello from bean
Code:
public class MyApplication {
private MyApplication() {
}
public static void main(String[] args) throws Exception {
Main main = new Main();
main.addConfigurationClass(MyConfiguration.class);
main.addRouteBuilder(MyRouteBuilder.class);
main.run(args);
}
}
public class MyConfiguration {
#BindToRegistry
public MyBean myBean(#PropertyInject("hi") String hi) {
return new MyBean(hi);
}
}
public class MyBean {
private String hi;
public MyBean(String hi) {
this.hi = hi;
}
public String hello() {
return hi + " from bean";
}
}
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
CamelContext context = getContext();
PropertiesComponent pc = context.getComponent("properties", PropertiesComponent.class);
pc.setEnvironmentVariableMode(PropertiesComponent.ENVIRONMENT_VARIABLES_MODE_OVERRIDE); //default is FALLBACK
System.out.println("System env var hi=" + System.getenv("hi"));
from("timer:foo?repeatCount=1")
.log("${properties:hi} from route")
.bean("myBean")
.log("${body}");
}
}
application.properties:
hi = Hello
The only way I could get it to work was to override Main#postProcessCamelContext -- is this really the way it is intended to use? Or is there a more idiomatic way?
public class MyApplication extends Main {
private MyApplication(String[] args) throws Exception {
addConfigurationClass(MyConfiguration.class);
addRouteBuilder(MyRouteBuilder.class);
run(args);
}
#Override
protected void postProcessCamelContext(CamelContext camelContext) throws Exception {
PropertiesComponent pc = camelContext.getComponent("properties", PropertiesComponent.class);
pc.setEnvironmentVariableMode(PropertiesComponent.ENVIRONMENT_VARIABLES_MODE_OVERRIDE);
super.postProcessCamelContext(camelContext);
}
public static void main(String[] args) throws Exception {
new MyApplication(args);
}
}
A suggestion to Camel development: Wouldn't it make more sense to set environmentVariableMode to override by default instead of fallback, especially when thinking about container deployments: Environment variables take precedence over system properties which take precedence over application configuration (e.g. application.properties)?
[1] https://github.com/apache/camel/blob/master/components/camel-properties/src/main/docs/properties-component.adoc
Yeah its better to have ENV override, you are welcome to log a JIRA and work on a github PR. We love contributions
http://camel.apache.org/support.html
I logged a ticket: https://issues.apache.org/jira/browse/CAMEL-13502
Okay this has now been implement to be the default mode, and you can also configure this from the application.properties file etc: https://github.com/apache/camel/blob/master/examples/camel-example-main/src/main/resources/application.properties#L23
And the issue with #PropertyInject has also been fixed, in Camel v3.0M3

Correlating messages on two Camel Routes

In my application I have a generic Camel Route such as the following
from("direct:something").to("direct:outgoing")
and then dynamically in my code I deploy another route:
from("direct:outgoing").process(processor)
When flowing from route 1 to route 2 a new Exchange will be created. Is there an idiomatic way to correlate both? Should I set EXCHANGE.Correlation_ID header on the first route before sending it out?
This should definitely all be processed on the one exchange. Run this test and you'll see the same camel Exchange, with the same properties, etc.
public class CamelExchangeTest {
public static void main(String[] args) throws Exception {
final Processor showExchangeIdProcessor = new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println(exchange.getExchangeId());
}
};
Main camelMain = new Main();
camelMain.addRouteBuilder(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("timer:foo?period=1s&repeatCount=1")
.log("excgabge created!")
.process(showExchangeIdProcessor)
.to("direct:outgoing")
;
from("direct:outgoing")
.log("outgoing!")
.process(showExchangeIdProcessor)
;
}
});
camelMain.run();
}
}
Output:
ID-MYPC-55760-1411129552791-0-2
ID-MYPC-55760-1411129552791-0-2
So something else is going on. When you say "direct:outgoing", do you mean exactly that or is it something different - a different component perhaps?
When you say the route is created dynamically, how exactly is that done, and when (and why?)
From the Camel doc:
Some EIP patterns will spin off a sub message, and in those cases, Camel will add a correlation id on the Exchange as a property with they key Exchange.CORRELATION_ID, which links back to the source Exchange. For example the Splitter, Multicast, Recipient List, and Wire Tap EIP does this.
Thus, Exchange.CORRELATION_ID is set by Camel and should not be set by your application. But feel free to set a custom header or property if you need to such as:
exchange.getIn().setProperty("myProperty", myIdentifier);

Getting ElementNotFound Exception in TestNG

The following code is for login and then click on Create quest Link. It does not click on the link and gives ElementNotFound exception and skips the test. It just logs in and logout. Please Help
public class Edit_Question {
WebDriver driver = new FirefoxDriver();#
BeforeTest
public void load() {
driver.get("Page url");
}
# Test
public void login() throws InterruptedException {
driver.findElement(By.id("userid")).sendKeys("4060#jhg.com");
driver.findElement(By.id("password")).sendKeys("mpcyn2");
driver.findElement(By.id("emLoginLink")).click();
Thread.sleep(10000);
}# Test
public void ques() throws InterruptedException {
//select create questions
driver.findElement(By.xpath("//xpath link")).click(); //throws ElementNotFound exception
Thread.sleep(5000);
}# Test
public void logout() {
//logout
driver.findElement(By.partialLinkText("SeeharackTest1, SherrodUATT")).click();
driver.findElement(By.id("logoutLink")).click();
}
# AfterSuite
public void close() {
driver.close();
}
}
The order of execution is not gauranteed. You need to use dependOnMethods to gaurantee order here. So ques should depend on login and logout should depend on ques to gaurantee the order of execution.
Other observations :
1. Try using #BeforeClass instead of #BeforeTest and #AfterClass instead of #AfterSuite
2. Avoid using sleeps wherever possible. Wait for a particular element instead.
3. Shouldn't this entire flow be one testcase?
Hope it helps.

Apache camel FTP standalone programme

Hello I am trying to write a simple standalone java FTP programme that downloads files from FTP server location to my local machine using Apache Camel. When I run is I see that it runs forever and the actual file transfer is not taking place. What could be the issue?
private static class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("sftp://serverIpAddress?password=passwd&binary=true")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
System.out.println("Invoked timer at " + new Date());
}
})
.tracing()
.to("file://localmachine/Users/localFtpOutput/")
;
}
}
Wild guess : don't you need to provide a username to access your ftp ?
from("sftp://username#serverIpAddress?password=passwd&binary=true")
If you don't camel will try to log with anonymous as username and will use no password (according to the doc)

Resources