Apache camel FTP standalone programme - apache-camel

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)

Related

How to use Apache Camel to get web page HTML

I want to do nothing more than use Camel to get the HTML of a web page and save it as a local text file. I have tried the below but it doesn't work - it never hits the process code and no file shows up. This seems like it should be fairly simple. What am I doing wrong?
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure()
{
from("jetty:https://2001:4998:124:1507::f001") // www.yahoo.com IP address
.process(new Processor() {
public void process(Exchange exchange) throws Exception
{
System.out.println( "Name="+ exchange.getIn().getBody() );
}
})
.to("file:C:\\temp\\folder2?fileName=web.txt");
}
});
context.start();
Thread.sleep(5000);
context.stop();
System.out.println( "Done" );
from("jetty:https://....") configures the Jetty consumer, which acts as a web server.
You should use a producer, E.g to("jetty:https://..."), to make client requests. Things can be simplified a bit by using the camel-http component instead of Jetty by adding a dependency like:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http</artifactId>
<version>your-camel-vesion-here</version>
</dependency>
Then the route could look like this. It uses the timer component to initiate the HTTP call:
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("timer:getHtml?repeatCount=1")
.to("https://www.yahoo.com")
.to("file:C:\\temp\\folder2?fileName=web.txt");
}
});
If you're using Camel 3.x then you'll also need to add a dependency for camel-timer to make the example work.

Unit testing with Apache Camel

I want to test below camel route. All the example which i find online has route starting with file, where as in my case i have a spring bean method which is getting called every few minutes and finally message is transformed and moved to jms as well as audit directory.
I am clue less on write test for this route.
All i have currently in my test case is
Mockito.when(tradeService.searchTransaction()).thenReturn(dataWithSingleTransaction);
from("quartz2://tsTimer?cron=0/20+*+8-18+?+*+MON,TUE,WED,THU,FRI+*")
.bean(TradeService.class)
.marshal()
.jacksonxml(true)
.to("jms:queue:out-test")
.to("file:data/test/audit")
.end();
Testing with Apache Camel and Spring-Boot is really easy.
Just do the following (the example below is an abstract example just to give you a hint how you can do it):
Write a Testclass
Use the Spring-Boot Annotations to configure the test class.
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
#RunWith(SpringRunner.class)
public class MyRouteTest {
#EndpointInject(uri = "{{sourceEndpoint}}")
private ProducerTemplate sourceEndpoint;
....
public void test() {
// send your body to the endpoint. See other provided methods too.
sourceEndpoint.sendBody([your input]);
}
}
In the src/test/application.properties:
Configure your Camel-Endpoints like the source and the target:
sourceEndpoint=direct:myTestSource
Hints:
It's good not to hardwire your start-Endpoint in the route directly when using spring-boot but to use the application.properties. That way it is easier to mock your endpoints for unit tests because you can change to the direct-Component without changing your source code.
This means instead of:
from("quartz2://tsTimer?cron=0/20+*+8-18+?+*+MON,TUE,WED,THU,FRI+*")
you should write:
from("{{sourceEndpoint}}")
and configure the sourceEndpoint in your application.properties:
sourceEndpoint=quartz2://tsTimer?cron=0/20+*+8-18+?+*+MON,TUE,WED,THU,FRI+*
That way you are also able to use your route for different situations.
Documentation
A good documentation about how to test with spring-boot can be found here: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
For Apache Camel: http://camel.apache.org/testing.html
#the hand of NOD Thanks for your hints, i was going into completely wrong direction. After reading your answer i was able to write the basic test and from this i think i can take it forward.
Appreciate your time, however i see that based on my route it should drop an XML file to audit directory which is not happening.
Look like intermediate steps are also getting mocked, without I specifying anything.
InterceptSendToMockEndpointStrategy - Adviced endpoint [xslt://trans.xslt] with mock endpoint [mock:xslt:trans.xslt]
INFO o.a.c.i.InterceptSendToMockEndpointStrategy - Adviced endpoint [file://test/data/audit/?fileName=%24%7Bheader.outFileName%7D] with mock endpoint [mock:file:test/data/audit/]
INFO o.a.camel.spring.SpringCamelContext - StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
TradePublisherRoute.java
#Override
public void configure() throws Exception {
logger.info("TradePublisherRoute.configure() : trade-publisher started configuring camel route.");
from("{{trade-publisher.sourceEndpoint}}")
.doTry()
.bean(tradeService)
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
String dateStr = Constant.dateFormatForFileName.format(new Date());
logger.info("this is getting executed : " + dateStr);
exchange.setProperty(Constant.KEY_INCOMING_XML_FILE_NAME, "REQ-" + dateStr + Constant.AUDIT_FILE_EXTENSION);
exchange.setProperty(Constant.KEY_OUTGOING_XML_FILE_NAME, "RESP-" + dateStr + Constant.AUDIT_FILE_EXTENSION);
}
})
.marshal()
.jacksonxml(true)
.wireTap("{{trade-publisher.requestAuditDir}}" + "${header.inFileName}")
.to("{{trade-publisher.xsltFile}}")
.to("{{trade-publisher.outboundQueue}}")
.to("{{trade-publisher.responseAuditDir}}" + "${header.outFileName}")
.bean(txnService, "markSuccess")
.endDoTry()
.doCatch(Exception.class)
.bean(txnService, "markFailure")
.log(LoggingLevel.ERROR, "EXCEPTION: ${exception.stacktrace}")
.end();
TradePublisherRouteTest.java
#ActiveProfiles("test")
#RunWith(CamelSpringBootRunner.class)
#SpringBootTest(classes = TradePublisherApplication.class)
#MockEndpoints
public class TradePublisherRouteTest {
#EndpointInject(uri = "{{trade-publisher.outboundQueue}}")
private MockEndpoint mockQueue;
#EndpointInject(uri = "{{trade-publisher.sourceEndpoint}}")
private ProducerTemplate producerTemplate;
#MockBean
TradeService tradeService;
private List<Transaction> transactions = new ArrayList<>();
#BeforeClass
public static void beforeClass() {
}
#Before
public void before() throws Exception {
Transaction txn = new Transaction("TEST001", "C001", "100", "JPM", new BigDecimal(100.50), new Date(), new Date(), 1000, "P");
transactions.add(txn);
}
#Test
public void testRouteConfiguration() throws Exception {
Mockito.when(tradeService.searchTransaction()).thenReturn(new Data(transactions));
producerTemplate.sendBody(transactions);
mockQueue.expectedMessageCount(1);
mockQueue.assertIsSatisfied(2000);
}
Please correct me if i am doing something wrong!

Can we provide a processor before onFallbackViaNetwork() in camel-hystrix-eip

I'm using camel-hystrix-eip in my project, I want a processor before my fallback, but it's not working
from("direct:sample").id("id:direct:sample").process(requestProcessor)
.hystrix()
.to(endPoint)
.onFallbackViaNetwork()
.to(fallback_endPoint)
I want to alter my fallback_endpoint using a processor, but seems like after onFallbackViaNetwork() we have to immediately provide to().
please suggest if there any way to do so.
I tried something like below, but it's not working.
from("direct:sample").id("id:direct:sample").process(requestProcessor)
.hystrix()
.to(endPoint)
.onFallbackViaNetwork()
.process(fallbackProcessor)
.to(fallback_endPoint)
Actually, I'm using requestProcessor to override the actual endpoint, and in case of a fallback, fallback_endPoint is also getting overridden, is there any way to avoid this.
You can have a processor after onFallbackViaNetwork(). You can also use the toD EIP to send the message to a dynamic endpoint.
Based on your code, you could set a Header MyEndpoint which contains your new endpoint string, and then reference it using .toD("${header.MyEndpoint}"). Repeat this pattern whenever you need to set a dynamic endpoint.
For example:
from("direct:sample")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
// do something
exchange.getIn().setHeader("EndpointHystrix", "mock:hystrix");
}
})
.hystrix()
.toD("${header.EndpointHystrix}")
.onFallbackViaNetwork()
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
// do something more
exchange.getIn().setHeader("EndpointFallback", "mock:fallback");
}
})
.toD("${header.EndpointFallback}")
.end()
.to("...");
I've tested this in Camel 2.20.0 and 2.21.0.

How to use Apache Camel exchange messages?

I am newcomer in Apache Camel. Please have a look to my code bellow:
I have a service which exposed as cxf webservice:
interface CxfService{
public OutputType hello(InputType input);
}
This is my route:
from("cxf:/test?serviceClass=" + CxfService.class.getName())
.to("log:cxfLog1")
.recipientList(simple("direct:${header.operationName}"));
from("direct:hello")
.process(new Processor(){
public void process(Exchange exchange) throws Exception {
InputType file = exchange.getIn().getBody(InputType.class);
exchange.getOut().setBody(new OutputType());
}
});
The code works as expected, it consume InputType and produce OutputType.
I want to borrow my body to do another stuffs, so i rewrite that like this:
from("cxf:/test?serviceClass=" + CxfService.class.getName())
.to("log:cxfLog1")
.recipientList(simple("direct:${header.operationName}"));
from("direct:hello")
.process(new Processor(){
public void process(Exchange exchange) throws Exception {
InputType file = exchange.getIn().getBody(InputType.class);
exchange.getOut().setHeader("header.temporary", new OutputType());
}
})
.to("some endpoint")
.setBody(simple("${header.temporary}"));
This webservice consume InputType and produce nothing. What wrong with that?
In your second piece of code, when setting the header.temporary, you should change two things:
setHeader("temporary", new OutputType()) - the 'header' prefix isn't
needed - you're addressing headers directly via the method call.
Use getIn() instead of getOut(). The input will get copied to the
output. You may want to do some research into the procedure for
Camel building the out message for details - I'm not 100% sure of
this one.
Change
exchange.getOut().setHeader("header.temporary", new OutputType());
To
exchange.getIn().setHeader("temporary"), new OutputType());
.setHeader() is when you use the simple language. In 99% of the cases getIn() is sufficient.

Camel first experience

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();
}
}

Resources