Book Image

Apache Camel Developer's Cookbook

Book Image

Apache Camel Developer's Cookbook

Overview of this book

Apache Camel is a de-facto standard for developing integrations in Java, and is based on well-understood Enterprise Integration Patterns. It is used within many commercial and open source integration products. Camel makes common integration tasks easy while still providing the developer with the means to customize the framework when the situation demands it. Tasks such as protocol mediation, message routing and transformation, and auditing are common usages of Camel. Apache Camel Developer's Cookbook provides hundreds of best practice tips for using Apache Camel in a format that helps you build your Camel projects. Each tip or recipe provides you with the most important steps to perform along with a summary of how it works, with references to further reading if you need more information. This book is intended to be a reliable information source that is quicker to use than an Internet search. Apache Camel Developer's Cookbook is a quick lookup guide that can also be read from cover to cover if you want to get a sense of the full power of Apache Camel. This book provides coverage of the full lifecycle of creating Apache Camel-based integration projects, including the structure of your Camel code and using the most common Enterprise Integration patterns. Patterns like Split/Join and Aggregation are covered in depth in this book. Throughout this book, you will be learning steps to transform your data. You will also learn how to perform unit and integration testing of your code using Camel's extensive testing framework, and also strategies for debugging and monitoring your code. Advanced topics like Error Handling, Parallel Processing, Transactions, and Security will also be covered in this book. This book provides you with practical tips on using Apache Camel based on years of hands-on experience from hundreds of integration projects.
Table of Contents (20 chapters)
Apache Camel Developer's Cookbook
Credits
About the Authors
Acknowledgments
About the Reviewers
www.PacktPub.com
Preface
Index

Controlling route startup and shutdown


When integration logic is composed of routes depending on other routes via direct:, it is important that they start up in such a way that dependencies are available before exchanges start flowing. If not, you are likely to see this sort of exception being thrown:

org.apache.camel.CamelExchangeException: No consumers available on endpoint: Endpoint[direct://someMissingEndpoint]

Conversely, on application shutdown, messages should complete processing gracefully rather than fail because a dependent route is no longer available. Camel provides a mechanism to define an order for startup and shutdown that addresses both of these issues at the same time.

This recipe will show you how to control the startup and shutdown order of your routes.

Getting ready

Define your desired routing logic as described in either the Using Camel in a Java application recipe, or the Embedding Camel in a Spring application recipe.

The Java code for this recipe is located in the org.camelcookbook.structuringroutes.routecontrol package.

How to do it...

Set the startupOrder property associated with the route.

In the XML DSL, add a startupOrder attribute to the route element:

<route startupOrder="20">
  <from uri="jms:queue:orders"/>
  <to uri="direct:processOrder"/>
</route>

<route startupOrder="10">
  <from uri="direct:processOrder"/>
  <process ref="orderProcessor"/>
</route>

In the Java DSL, call the startupOrder(..) method after the from statement:

from("jms:queue:orders").startupOrder(20)
  .to("direct:processOrder");

from("direct:processOrder").startupOrder(10)
  .process(new OrderProcessor());

How it works...

Routes are started in ascending startupOrder. In the preceding examples, the direct: route will be started before the main entry point to the integration, which consumes from JMS.

You can assign any integer greater than 0 and less than 1,000 to the startupOrder. You cannot assign the same value more than once in a Camel context, otherwise it will refuse to start up. Camel will automatically assign values greater than 1,000 to any routes that do not specifically have one defined.

Tip

Drawing inspiration from BASIC programming (for those old enough to remember it), it is useful to assign startupOrder values in increments of 10. As your integration grows and you find yourself breaking routes down for reuse, it pays to have numbers available so that you do not have to renumber every route.

When you shut down the application, Camel will turn off the routes in the reverse order to that in which it started them. Routes are turned off in descending order.

When a route shuts down, the endpoint consumer is first turned off, and any messages that are flowing through the route ("in-flight") are allowed to complete before the route itself is shut down. Any messages that remain in-flight will be discarded after a timeout of 300 seconds. The timeout is configurable on the Camel context's associated ShutdownStrategy.

There's more...

Routes can be started and shut down programmatically through the CamelContext startRoute() and stopRoute() methods. Since the context is accessible through an Exchange it is possible to perform custom route control logic. Take, as an example, the following class that stops a route whose name is specified by the body of the exchange:

public class RouteStoppingProcessor implements Processor {
  @Override
  public void process(Exchange exchange) throws Exception {
    final String routeName = 
        exchange.getIn().getBody(String.class);
    final CamelContext context = exchange.getContext();
    new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          context.stopRoute(routeName);
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
      }
    }).start();
  }
}

Note

It is best practice to manually shut down routes in Camel in a separate thread than in the one that is processing the exchange. The reason behind this is that Camel waits for all exchanges that are flowing through a route to complete before it stops the route. If a thread processing an exchange attempts to shut down the route through which that exchange is flowing, this results in a deadlock.

See the following for more details: http://camel.apache.org/how-can-i-stop-a-route-from-a-route.html.

Routes can also be stopped and started through the use of a Control Bus endpoint:

from("direct:in").id("mainRoute")
  .log("Stopping route")
  .to("controlbus:route?routeId=mainRoute&action=stop&async=true")
  .log("Signalled to stop route")
  .to("mock:out");

Tip

Note the use of async=true to shut down the route in a background thread and thereby prevent a deadlock.

Manual route control does not take into account the startupOrder, so you must take care when performing it that any routes that you start up or shut down are controlled in an orderly manner.

Routes can be turned off at startup by setting the autoStartup attribute to false.

In the XML DSL, add an autoStartup attribute to the route element:

<route autoStartup="false">
  <from uri="jms:queue:orders"/>
  <!-- ... -->
</route>

In the Java DSL, call the autoStartup(..) method after the from statement:

from("jms:queue:orders").autoStartup(false)...

You would use this feature if you want to control route availability manually, or through a route policy.

A RoutePolicy is an interface that you can build upon to determine whether routes should be running or not. Camel provides route policies out of the box for throttling routes (ThrottlingInflightRoutePolicy), defining uptime through a timer (SimpleScheduledRoutePolicy), and cron expressions (CronScheduledRoutePolicy).