blob: b6926f21a65039276e645ce58a96441e5c2317ab [file] [log] [blame]
[[chapter-getting-started]]
[[BookGettingStarted-GettingStartedwithApacheCamel]]
Getting Started with Apache Camel
---------------------------------
[[BookGettingStarted-eip-book]]
[[BookGettingStarted-TheEnterpriseIntegrationPatternsEIPBook]]
The _Enterprise Integration Patterns_ (EIP) book
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The purpose of a _patterns_ book is not to advocate new techniques that
the authors have invented, but rather to document existing best
practices within a particular field. By doing this, the authors of a
patterns book hope to spread knowledge of best practices and promote a
vocabulary for discussing architectural designs. +
One of the most famous patterns books is
http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612[_Design
Patterns: Elements of Reusable Object-oriented Software_] by Erich
Gamma, Richard Helm, Ralph Johnson and John Vlissides, commonly known as
the http://en.wikipedia.org/wiki/Design_Patterns["Gang of Four" (GoF)]
book. Since the publication of __Design Patterns__, many other pattern
books, of varying quality, have been written. One famous patterns book
is called
http://www.amazon.com/Enterprise-Integration-Patterns-Designing-Deploying/dp/0321200683[_Enterprise
Integration Patterns: Designing, Building, and Deploying Messaging
Solutions_] by Gregor Hohpe and Bobby Woolf. It is common for people to
refer to this book by its initials __EIP__. As the subtitle of EIP
suggests, the book focuses on design patterns for asynchronous messaging
systems. The book discusses 65 patterns. Each pattern is given a textual
name and most are also given a graphical symbol, intended to be used in
architectural diagrams.
[[BookGettingStarted-TheCamelproject]]
The Camel project
~~~~~~~~~~~~~~~~~
Camel (http://camel.apache.org) is an open-source, Java-based project
that helps the user implement many of the design patterns in the EIP
book. Because Camel implements many of the design patterns in the EIP
book, it would be a good idea for people who work with Camel to have the
EIP book as a reference.
[[BookGettingStarted-OnlinedocumentationforCamel]]
Online documentation for Camel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The documentation is all under the Documentation category on the
right-side menu of the Camel website (also available in
http://camel.apache.org/manual.html[PDF form]).
link:books.html[Camel-related books] are also available, in particular
the http://manning.com/ibsen[Camel in Action] book, presently serving as
the Camel bible -- it has a
http://www.manning.com/ibsen/chapter1sample.pdf[free Chapter One (pdf)],
which is highly recommended to read to get more familiar with Camel.
[[BookGettingStarted-Ausefultipfornavigatingtheonlinedocumentation]]
A useful tip for navigating the online documentation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The breadcrumbs at the top of the online Camel documentation can help
you navigate between parent and child subsections. +
For example, If you are on the "Languages" documentation page then the
left-hand side of the reddish bar contains the following links.
[source,brush:,java;,gutter:,false;,theme:,Default]
----
Apache Camel > Documentation > Architecture > Languages
----
As you might expect, clicking on "Apache Camel" takes you back to the
home page of the Apache Camel project, and clicking on "Documentation"
takes you to the main documentation page. You can interpret the
"Architecture" and "Languages" buttons as indicating you are in the
"Languages" section of the "Architecture" chapter. Adding browser
bookmarks to pages that you frequently reference can also save time.
[[BookGettingStarted-online-javadoc-docs]]
[[BookGettingStarted-OnlineJavadocdocumentation]]
Online Javadoc documentation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Apache Camel website provides
http://camel.apache.org/maven/current/camel-core/apidocs/index.html[Javadoc
documentation]. It is important to note that the Javadoc documentation
is spread over several _independent_ Javadoc hierarchies rather than
being all contained in a single Javadoc hierarchy. In particular, there
is one Javadoc hierarchy for the _core_ APIs of Camel, and a separate
Javadoc hierarchy for each component technology supported by Camel. For
example, if you will be using Camel with ActiveMQ and FTP then you need
to look at the Javadoc hierarchies for the
http://camel.apache.org/maven/current/camel-core/apidocs/index.html[core
API] and
http://camel.apache.org/maven/current/camel-spring/apidocs/index.html[Spring
API].
[[BookGettingStarted-ConceptsandterminologyfundamentaltoCamel]]
Concepts and terminology fundamental to Camel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In this section some of the concepts and terminology that are
fundamental to Camel are explained. This section is not meant as a
complete Camel tutorial, but as a first step in that direction.
[[BookGettingStarted-endpoint]]
[[BookGettingStarted-Endpoint]]
Endpoint
^^^^^^^^
The term _endpoint_ is often used when talking about inter-process
communication. For example, in client-server communication, the client
is one endpoint and the server is the other endpoint. Depending on the
context, an endpoint might refer to an _address_, such as a `host:port`
pair for TCP-based communication, or it might refer to a _software
entity_ that is contactable at that address. For example, if somebody
uses `www.example.com:80` as an example of an endpoint, they might be
referring to the actual port at that host name (that is, an address), or
they might be referring to the web server (that is, software contactable
at that address). Often, the distinction between the address and
software contactable at that address is not an important one.
Some middleware technologies make it possible for several software
entities to be contactable at the same physical address. For example,
CORBA is an object-oriented, remote-procedure-call (RPC) middleware
standard. If a CORBA server process contains several objects then a
client can communicate with any of these objects at the same _physical_
address (host:port), but a client communicates with a particular object
via that object's _logical_ address (called an _IOR_ in CORBA
terminology), which consists of the physical address (`host:port`) plus an
id that uniquely identifies the object within its server process. (An
IOR contains some additional information that is not relevant to this
present discussion.) When talking about CORBA, some people may use the
term "endpoint" to refer to a CORBA server's _physical address_, while
other people may use the term to refer to the _logical address_ of a
single CORBA object, and other people still might use the term to refer
to any of the following:
* The physical address (`host:port`) of the CORBA server process
* The logical address (`host:port` plus `id`) of a CORBA object
* The CORBA server process (a relatively heavyweight software entity)
* A CORBA object (a lightweight software entity)
Because of this, you can see that the term _endpoint_ is ambiguous in at
least two ways. First, it is ambiguous because it might refer to an
address or to a software entity contactable at that address. Second, it
is ambiguous in the _granularity_ of what it refers to: a heavyweight
versus lightweight software entity, or physical address versus logical
address. It is useful to understand that different people use the term
_endpoint_ in slightly different (and hence ambiguous) ways because
Camel's usage of this term might be different to whatever meaning you
had previously associated with the term.
Camel provides out-of-the-box support for endpoints implemented with
many different communication technologies. Here are some examples of the
Camel-supported endpoint technologies.
* A JMS queue.
* A web service.
* A file. A file may sound like an unlikely type of endpoint, until you
realize that in some systems one application might write information to
a file and, later, another application might read that file.
* An FTP server.
* An email address. A client can send a message to an email address, and
a server can read an incoming message from a mail server.
* A POJO (plain old Java object).
In a Camel-based application, you create (Camel wrappers around) some
endpoints and connect these endpoints with __routes__, which I will
discuss later in link:book-getting-started.html[Section 4.8 ("Routes,
RouteBuilders and Java DSL")]. Camel defines a Java interface called
`Endpoint`. Each Camel-supported endpoint has a class that implements
this `Endpoint` interface. As I discussed in
link:book-getting-started.html[Section 3.3 ("Online Javadoc
documentation")], Camel provides a separate Javadoc hierarchy for each
communications technology supported by Camel. Because of this, you will
find documentation on, say, the `JmsEndpoint` class in the
http://camel.apache.org/maven/current/camel-jms/apidocs/[JMS Javadoc
hierarchy], while documentation for, say, the `FtpEndpoint` class is in
the http://camel.apache.org/maven/current/camel-ftp/apidocs/[FTP Javadoc
hierarchy].
[[BookGettingStarted-CamelContext]]
CamelContext
^^^^^^^^^^^^
A `CamelContext` object represents the Camel runtime system. You
typically have one `CamelContext` object in an application. A typical
application executes the following steps:
1. Create a `CamelContext` object.
2. Add endpoints – and possibly components, which are discussed in
link:book-getting-started.html[Section 4.5 ("Components")] – to the
`CamelContext` object.
3. Add routes to the `CamelContext` object to connect the endpoints.
4. Invoke the `start()` operation on the `CamelContext` object. This
starts Camel-internal threads that are used to process the sending,
receiving and processing of messages in the endpoints.
5. Eventually invoke the `stop()` operation on the `CamelContext`
object. Doing this gracefully stops all the endpoints and Camel-internal
threads.
Note that the `CamelContext.start()` operation does not block
indefinitely. Rather, it starts threads internal to each `Component` and
`Endpoint` and then `start()` returns. Conversely, `CamelContext.stop()`
waits for all the threads internal to each `Endpoint` and `Component` to
terminate and then `stop()` returns.
If you neglect to call `CamelContext.start()` in your application then
messages will not be processed because internal threads will not have
been created.
If you neglect to call `CamelContext.stop()` before terminating your
application then the application may terminate in an inconsistent state.
If you neglect to call `CamelContext.stop()` in a JUnit test then the
test may fail due to messages not having had a chance to be fully
processed.
[[BookGettingStarted-CamelTemplate]]
CamelTemplate
^^^^^^^^^^^^^
Camel used to have a class called `CamelClient`, but this was renamed to
be `CamelTemplate` to be similar to a naming convention used in some
other open-source projects, such as the `TransactionTemplate` and
`JmsTemplate` classes in http://www.springframework.org/[Spring].
The `CamelTemplate` class is a thin wrapper around the `CamelContext`
class. It has methods that send a `Message` or `Exchange` – both
discussed in link:book-getting-started.html[Section 4.6 ("Message and
Exchange")]) – to an `Endpoint` – discussed in
link:book-getting-started.html[Section 4.1 ("Endpoint")]. This provides
a way to enter messages into source endpoints, so that the messages will
move along routes – discussed in link:book-getting-started.html[Section
4.8 ("Routes, RouteBuilders and Java DSL")] – to destination endpoints.
[[BookGettingStarted-url-uri-urn-iri]]
[[BookGettingStarted-TheMeaningofURL,URI,URNandIRI]]
The Meaning of URL, URI, URN and IRI
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Some Camel methods take a parameter that is a _URI_ string. Many people
know that a URI is "something like a URL" but do not properly understand
the relationship between URI and URL, or indeed its relationship with
other acronyms such as IRI and URN.
Most people are familiar with _URLs_ (uniform resource locators), such
as `http://...`, `ftp://...`, `mailto:...`. Put simply, a URL specifies
the _location_ of a resource.
A _URI_ (uniform resource identifier) is a URL _or_ a URN. So, to fully
understand what URI means, you need to first understand what is a URN. +
_URN_ is an acronym for __uniform resource name__. There are may "unique
identifier" schemes in the world, for example, ISBNs (globally unique
for books), social security numbers (unique within a country), customer
numbers (unique within a company's customers database) and telephone
numbers. Each "unique identifier" scheme has its own notation. A URN is
a wrapper for different "unique identifier" schemes. The syntax of a URN
is `urn:<scheme-name>:<unique-identifier>`. A URN uniquely identifies a
_resource_, such as a book, person or piece of equipment. By itself, a
URN does not specify the _location_ of the resource. Instead, it is
assumed that a _registry_ provides a mapping from a resource's URN to
its location. The URN specification does not state what form a registry
takes, but it might be a database, a server application, a wall chart or
anything else that is convenient. Some hypothetical examples of URNs are
`urn:employee:08765245`, `urn:customer:uk:3458:hul8` and
`urn:foo:0000-0000-9E59-0000-5E-2`. The `<scheme-name>` (`employee`,
`customer` and `foo` in these examples) part of a URN implicitly defines
how to parse and interpret the `<unique-identifier>` that follows it. An
arbitrary URN is meaningless unless: (1) you know the semantics implied
by the `<scheme-name>`, and (2) you have access to the registry
appropriate for the `<scheme-name>`. A registry does not have to be public
or globally accessible. For example, `urn:employee:08765245` might be
meaningful only within a specific company.
To date, URNs are not (yet) as popular as URLs. For this reason, URI is
widely misused as a synonym for URL.
_IRI_ is an acronym for __internationalized resource identifier__. An
IRI is simply an internationalized version of a URI. In particular, a
URI can contain letters and digits in the US-ASCII character set, while
a IRI can contain those same letters and digits, and _also_ European
accented characters, Greek letters, Chinese ideograms and so on.
[[BookGettingStarted-Components]]
Components
^^^^^^^^^^
_Component_ is confusing terminology; _EndpointFactory_ would have been
more appropriate because a `Component` is a factory for creating
`Endpoint` instances. For example, if a Camel-based application uses
several JMS queues then the application will create one instance of the
`JmsComponent` class (which implements the `Component` interface), and
then the application invokes the `createEndpoint()` operation on this
`JmsComponent` object several times. Each invocation of
`JmsComponent.createEndpoint()` creates an instance of the `JmsEndpoint`
class (which implements the `Endpoint` interface). Actually,
application-level code does not invoke `Component.createEndpoint()`
directly. Instead, application-level code normally invokes
`CamelContext.getEndpoint()`; internally, the `CamelContext` object
finds the desired `Component` object (as I will discuss shortly) and
then invokes `createEndpoint()` on it.
Consider the following code:
[source,java]
----
myCamelContext.getEndpoint("pop3://john.smith@mailserv.example.com?password=myPassword");
----
The parameter to `getEndpoint()` is a URI. The URI _prefix_ (that is,
the part before `:`) specifies the name of a component. Internally, the
`CamelContext` object maintains a mapping from names of components to
`Component` objects. For the URI given in the above example, the
`CamelContext` object would probably map the `pop3` prefix to an
instance of the `MailComponent` class. Then the `CamelContext` object
invokes
`createEndpoint("pop3://john.smith@mailserv.example.com?password=myPassword")`
on that `MailComponent` object. The `createEndpoint()` operation splits
the URI into its component parts and uses these parts to create and
configure an `Endpoint` object. +
In the previous paragraph, I mentioned that a `CamelContext` object
maintains a mapping from component names to `Component` objects. This
raises the question of how this map is populated with named `Component`
objects. There are two ways of populating the map. The first way is for
application-level code to invoke
`CamelContext.addComponent(String componentName, Component component)`.
The example below shows a single `MailComponent` object being registered
in the map under 3 different names.
[source,java]
----
Component mailComponent = new org.apache.camel.component.mail.MailComponent();
myCamelContext.addComponent("pop3", mailComponent);
myCamelContext.addComponent("imap", mailComponent);
myCamelContext.addComponent("smtp", mailComponent);
----
The second (and preferred) way to populate the map of named `Component`
objects in the `CamelContext` object is to let the `CamelContext` object
perform lazy initialization. This approach relies on developers
following a convention when they write a class that implements the
`Component` interface. I illustrate the convention by an example. Let's
assume you write a class called `com.example.myproject.FooComponent` and
you want Camel to automatically recognize this by the name `foo`. To do
this, you have to write a properties file called
`META-INF/services/org/apache/camel/component/foo` (without a
`.properties` file extension) that has a single entry in it called
`class`, the value of which is the fully-scoped name of your class. This
is shown below:
.META-INF/services/org/apache/camel/component/foo
[source]
----
class=com.example.myproject.FooComponent
----
If you want Camel to also recognize the class by the name `bar` then you
write another properties file in the same directory called `bar` that
has the same contents. Once you have written the properties file(s), you
create a JAR file that contains the `com.example.myproject.FooComponent`
class and the properties file(s), and you add this jar file to your
CLASSPATH. Then, when application-level code invokes
`createEndpoint("foo:...")` on a `CamelContext` object, Camel will find
the "foo"" properties file on the CLASSPATH, get the value of the
`class` property from that properties file, and use reflection APIs to
create an instance of the specified class.
As I said in link:book-getting-started.html[Section 4.1 ("Endpoint")],
Camel provides out-of-the-box support for numerous communication
technologies. The out-of-the-box support consists of classes that
implement the `Component` interface plus properties files that enable a
`CamelContext` object to populate its map of named `Component`
objects.
Earlier in this section I gave the following example of calling
`CamelContext.getEndpoint()`:
[source,java]
----
myCamelContext.getEndpoint("pop3://john.smith@mailserv.example.com?password=myPassword");
----
When I originally gave that example, I said that the parameter to
`getEndpoint()` was a URI. I said that because the online Camel
documentation and the Camel source code both claim the parameter is a
URI. In reality, the parameter is restricted to being a URL. This is
because when Camel extracts the component name from the parameter, it
looks for the first ":", which is a simplistic algorithm. To understand
why, recall from link:book-getting-started.html[Section 4.4 ("The
Meaning of URL, URI, URN and IRI")] that a URI can be a URL _or_ a URN.
Now consider the following calls to `getEndpoint`:
[source,java]
----
myCamelContext.getEndpoint("pop3:...");
myCamelContext.getEndpoint("jms:...");
myCamelContext.getEndpoint("urn:foo:...");
myCamelContext.getEndpoint("urn:bar:...");
----
Camel identifies the components in the above example as `pop3`, `jms`,
`urn` and `urn`. It would be more useful if the latter components were
identified as `urn:foo` and `urn:bar` or, alternatively, as `foo` and
`bar` (that is, by skipping over the `urn:` prefix). So, in practice you
must identify an endpoint with a URL (a string of the form
`<scheme>:...`) rather than with a URN (a string of the form
`urn:<scheme>:...`). This lack of proper support for URNs means the you
should consider the parameter to `getEndpoint()` as being a URL rather
than (as claimed) a URI.
[[BookGettingStarted-message-and-exchange]]
[[BookGettingStarted-MessageandExchange]]
Message and Exchange
^^^^^^^^^^^^^^^^^^^^
The `Message` interface provides an abstraction for a single message,
such as a request, reply or exception message.
There are concrete classes that implement the `Message` interface for
each Camel-supported communications technology. For example, the
`JmsMessage` class provides a JMS-specific implementation of the
`Message` interface. The public API of the `Message` interface provides
get- and set-style methods to access the _message id_, _body_ and
individual _header_ fields of a message.
The `Exchange` interface provides an abstraction for an exchange of
messages, that is, a request message and its corresponding reply or
exception message. In Camel terminology, the request, reply and
exception messages are called _in_, _out_ and _fault_ messages.
There are concrete classes that implement the `Exchange` interface for
each Camel-supported communications technology. For example, the
`JmsExchange` class provides a JMS-specific implementation of the
`Exchange` interface. The public API of the `Exchange` interface is
quite limited. This is intentional, and it is expected that each class
that implements this interface will provide its own technology-specific
operations.
Application-level programmers rarely access the `Exchange` interface (or
classes that implement it) directly. However, many classes in Camel are
generic types that are instantiated on (a class that implements)
`Exchange`. Because of this, the `Exchange` interface appears a lot in
the generic signatures of classes and methods.
[[BookGettingStarted-Processor]]
Processor
^^^^^^^^^
The `Processor` interface represents a class that processes a message.
The signature of this interface is shown below:
.Processor
[source,java]
----
package org.apache.camel;
public interface Processor {
void process(Exchange exchange) throws Exception;
}
----
Notice that the parameter to the `process()` method is an `Exchange`
rather than a `Message`. This provides flexibility. For example, an
implementation of this method initially might call `exchange.getIn()` to
get the input message and process it. If an error occurs during
processing then the method can call `exchange.setException()`.
An application-level developer might implement the `Processor` interface
with a class that executes some business logic. However, there are many
classes in the Camel library that implement the `Processor` interface in
a way that provides support for a design pattern in the
link:book-getting-started.html[EIP book]. For example, `ChoiceProcessor`
implements the message router pattern, that is, it uses a cascading
if-then-else statement to route a message from an input queue to one of
several output queues. Another example is the `FilterProcessor` class
which discards messages that do not satisfy a stated _predicate_ (that
is, condition).
[[BookGettingStarted-routes]]
[[BookGettingStarted-Routes,RouteBuildersandJavaDSL]]
Routes, RouteBuilders and Java DSL
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A _route_ is the step-by-step movement of a `Message` from an input
queue, through arbitrary types of decision making (such as filters and
routers) to a destination queue (if any). Camel provides two ways for an
application developer to specify routes. One way is to specify route
information in an XML file. A discussion of that approach is outside the
scope of this document. The other way is through what Camel calls a Java
_DSL_ (domain-specific language).
[[BookGettingStarted-IntroductiontoJavaDSL]]
Introduction to Java DSL
++++++++++++++++++++++++
For many people, the term "domain-specific language" implies a compiler
or interpreter that can process an input file containing keywords and
syntax specific to a particular domain. This is _not_ the approach taken
by Camel. Camel documentation consistently uses the term "Java DSL"
instead of "DSL", but this does not entirely avoid potential confusion.
The Camel "Java DSL" is a class library that can be used in a way that
looks almost like a DSL, except that it has a bit of Java syntactic
baggage. You can see this in the example below. Comments afterwards
explain some of the constructs used in the example.
.*Example of Camel's "Java DSL"*
[source,java]
----
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("queue:a").filter(header("foo").isEqualTo("bar")).to("queue:b");
from("queue:c").choice()
.when(header("foo").isEqualTo("bar")).to("queue:d")
.when(header("foo").isEqualTo("cheese")).to("queue:e")
.otherwise().to("queue:f");
}
};
CamelContext myCamelContext = new DefaultCamelContext();
myCamelContext.addRoutes(builder);
----
The first line in the above example creates an object which is an
instance of an anonymous subclass of `RouteBuilder` with the specified
`configure()` method.
The `CamelContext.addRoutes(RouterBuilder builder)` method invokes
`builder.setContext(this)` – so the `RouteBuilder` object knows which
`CamelContext` object it is associated with – and then invokes
`builder.configure()`. The body of `configure()` invokes methods such as
`from()`, `filter()`, `choice()`, `when()`, `isEqualTo()`, `otherwise()`
and `to()`.
The `RouteBuilder.from(String uri)` method invokes `getEndpoint(uri)` on
the `CamelContext` associated with the `RouteBuilder` object to get the
specified `Endpoint` and then puts a `FromBuilder` _wrapper_ around this
`Endpoint`. The `FromBuilder.filter(Predicate predicate)` method creates
a `FilterProcessor` object for the `Predicate` (that is, condition)
object built from the `header("foo").isEqualTo("bar")` expression. In
this way, these operations incrementally build up a `Route` object (with
a `RouteBuilder` wrapper around it) and add it to the `CamelContext`
object associated with the `RouteBuilder`.
[[BookGettingStarted-CritiqueofJavaDSL]]
Critique of Java DSL
++++++++++++++++++++
The online Camel documentation compares Java DSL favorably against the
alternative of configuring routes and endpoints in a XML-based Spring
configuration file. In particular, Java DSL is less verbose than its XML
counterpart. In addition, many integrated development environments
(IDEs) provide an auto-completion feature in their editors. This
auto-completion feature works with Java DSL, thereby making it easier
for developers to write Java DSL.
However, there is another option that the Camel documentation neglects
to consider: that of writing a parser that can process DSL stored in,
say, an external file. Currently, Camel does not provide such a DSL
parser, and I do not know if it is on the "to do" list of the Camel
maintainers. I think that a DSL parser would offer a significant benefit
over the current Java DSL. In particular, the DSL would have a syntactic
definition that could be expressed in a relatively short BNF form. The
effort required by a Camel user to learn how to use DSL by reading this
BNF would almost certainly be significantly less than the effort
currently required to study the API of the `RouterBuilder` classes.
[[BookGettingStarted-ContinueLearningaboutCamel]]
Continue Learning about Camel
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Return to the main link:getting-started.html[Getting Started] page for
additional introductory reference information.