6

I'm trying to use Apache Camel to download and route files from an FTP server. However, files are only added to the FTP server once in a long while so having the program running continuously seems a bit overzealous. Instead, I would rather have a cronjob that runs weekly and processes any new files that have been added to the server.

Is there any way to get Camel to automatically shutdown once it no longer has any new files to process?

My current main function looks like this:

public static void main (String[] args) throws Exception {
    org.apache.camel.spring.Main main = new org.apache.camel.spring.Main ();
    main.setApplicationContextUri ("applicationContext.xml");
    main.enableHangupSupport ();
    main.run (args);
}

And the interesting part of the applicationContext.xml is:

<camelContext>
    <route>
        <from uri="ftp://ftp.example.com/remoteDir?username=user&amp;password=pass"/>
        <to uri="file:../ftp_data?tempPrefix=."/>
    </route>
</camelContext>
Keith
  • 518
  • 1
  • 6
  • 10

3 Answers3

5

Adding this example that may be useful to others without digging all the examples in the link.

Define a bean/processor that will launch a separate thread. This new thread will call stop() on the active CamelContext.

public class ShutdownBean {

    private final static Logger log = LoggerFactory.getLogger(ShutdownBean.class);

    public void process(Exchange exchange) throws Exception {
        final CamelContext camelContext = exchange.getContext();

        Thread shutdownThread = new Thread(() -> {
            Thread.currentThread().setName("ShutdownThread");
            try {
                camelContext.stop();
            } catch (Exception e) {
                log.error("Errore during shutdown", e);
            }
        });

        shutdownThread.start();
    }
}

In your application context define this route and call it when you need to shutdown Camel.

<bean id="shutdownBean"
      class="your.package.ShutdownBean" />

<camelContext>

    <route id="ShutdownRoute">
        <from uri="direct:shutdown" />
        <log message="Shutdown..." />
        <to uri="bean:shutdownBean" />
    </route>

</camelContext>

Note: enableHangupSupport() is deprecated on newer Camel versions: is enabled by default now, so no longer need to call this method.

Alessandro Da Rugna
  • 4,571
  • 20
  • 40
  • 64
  • This should be the new accepted answer. I have this working in that it shuts down the route but I'm looking for a way to exit the entire camel process itself. Any ideas? – Luiz Sep 03 '16 at 00:22
  • My solution stops the entire `CamelContext`. If you use Spring integration this should also quit the entire application. How do you run Camel? – Alessandro Da Rugna Sep 04 '16 at 14:00
  • You're right I do see the `CamelContext` shutting down. Camel is being started via a gradle task but when it shuts down the task seems to just hang. Does Camel not shutdown with an exit code perhaps? This might be more of a gradle question now. – Luiz Sep 06 '16 at 13:08
  • 2
    Update: So the problem ended up having to do with options not being attached to a file component correctly. I had uri="file://path/to/dir?option1=val1?option2=val2 where instead it should be uri="file://path/to/dir?option1=val1&option2=val2. No error was being thrown frustraingly; the task would just hang after camelContext would shutdown. Also turns out that escaping the "&" symbol via & is very important. – Luiz Sep 07 '16 at 20:44
4

See this FAQ how to stop a route from a route: http://camel.apache.org/how-can-i-stop-a-route-from-a-route.html.

Then you can enable the option: sendEmptyMessageWhenIdle=true, and then in the route do a message filter, or content based route, and detect the empty message, and then stop the route and then after that CamelContext.

Though I also think this question has been discussed before, so you can maybe find other SO questions or google etc. As there is also alternative ways of doing this.

Claus Ibsen
  • 56,060
  • 7
  • 50
  • 65
2

Completing Claus answer, this code run in a only once fashioned way Main:

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.main.Main;

public class MyMainRouter extends RouteBuilder {

  static Main main;

  @Override
  public void configure() throws Exception {
    from("timer:foo?delay=5s")
        .log("Hello camel, main world after 5 seconds!")
        .process(processor -> main.completed());
  }

  public static void main(String[] args) throws Exception {
    main = new Main();
    main.addRouteBuilder(new MyMainRouter());
    main.run();
  }

}

After 5 seconds, the code will run only once, because we will call a processor that will call completed() method, wich internally have CountDownLatch stopping a route pattern from another thread.

Valtoni Boaventura
  • 1,519
  • 12
  • 13