Creating a simple web service in Apache Camel using Jetty
Introducing the Jetty component
While Apache Camel’s HTTP component is useful for consuming simple web services, Camel’s Jetty component (camel-jetty
) is used for exposing an HTTP endpoint, suitable for providing a simple web service.
Jetty is most commonly used as the start component in a Camel route. The URI format for the component is:
jetty:http://{ip_address}:{port}/{path}
Where ip_address is the address that Jetty should listen on, port is the HTTP port number, and path is the path of the endpoint. For example:
jetty:http://0.0.0.0:8080/myservice
Tip: Specifying 0.0.0.0
as the hostname means that Jetty will listen on all available IP addresses. This is useful if you want your web service to be available externally. If you just use 127.0.0.1
then the web service will only be available locally.
The Jetty component isn’t included in camel-core
, so camel-jetty
and all its dependencies need to be on your classpath. Or, if you’re using Maven, just add the following to your project’s POM:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty</artifactId>
<version>{your_camel_version_goes_here}</version>
</dependency>
Note: Jetty is ideally suited for simple web services, like the examples below. If you want to build more complex, structured web services, like SOAP and REST services, have a look at Camel’s CXF and CXF-RS components.
Some simple Camel Jetty examples
OK, let’s create some simple services using Jetty!
To create the examples in this tutorial, I’m using IntelliJ IDEA Community Edition as my IDE. (No reason, just fancied a bit of variety…)
If you’re not yet familiar with how to create a Camel project in IntelliJ, then please follow the mini tutorial below.
Tip: On MacOS X, the cleanest way to install IntelliJ IDEA Community Edition (CE) is via Homebrew. Homebrew is a package manager for MacOS, maintained by the community. First install Homebrew, and then, from a Terminal window, type:
$ brew tap caskroom/versions
$ brew cask install intellij-idea-ce
This will install IntelliJ IDEA Community Edition into your Applications folder.
Creating an empty Camel project in IntelliJ IDEA
You can use Camel in several different ways, but one of the most common is to write your routes using Java DSL. This is where you use standard Java syntax for declaring a route, by building methods together – e.g. from("start_component").to("end_component")
.
The following two options will create projects using Camel’s Java Maven archetype (camel-archetype-java
). The archetype is effectively a template for a Java Camel project. It sets everything up for you. It creates a shell project containing a very simple route, and a Java main()
method, so the route can be run from the command line like any simple Java program.
Option 1: Create a Camel project using the Maven wizard in IntelliJ IDEA
Assuming you have IntelliJ IDEA installed, create a new Camel project using the following steps:
-
Open IntelliJ IDEA.
-
Choose New Project from the splash screen (or from the File menu, choose New Project).
-
Tick Create from Archetype and, from the archetype list, select
org.apache.camel.archetypes:camel-archetype-java
. Click Next. -
Give a groupId (e.g.
com.example
) and an artifactId (e.g.MyCamelRoute
) and click Next. -
Click Next to accept the Maven settings.
-
Give your IntelliJ IDEA project a name and then click Finish.
-
IDEA will run Maven to create a new project from the archetype, and download the relevant dependencies.
Note: IDEA may ask you to Enable Maven imports before continuing. You should accept this prompt.
Problems downloading dependencies? Maven will try to download lots of dependencies as it creates the project. If you encounter difficulty at this point, check your internet connection, especially if you’re behind a corporate proxy.
Option 2: Create a Camel project using the Maven command line, then import into IntelliJ IDEA
If Terminal is your thing, you can create a project at the command line using Maven:
- Firstly, make sure Maven is installed and that the
mvn
command is available on yourPATH
. (Tip: runmvn --version
at the command line to check.) - Open a Terminal or Command Prompt.
cd
to your workspace folder. (You don’t need to create a new folder for your project, because Maven will do that for you.)- Run
mvn archetype:generate -DarchetypeGroupId=org.apache.camel.archetypes -DarchetypeArtifactId=camel-archetype-java
. Then, when prompted: – groupId: (pick a unique package name – I usecom.cleverbuilder
)
– artifactId: (give the name of your project – e.g.MyRestProject
)
– version: (accept the default)
– package: (just press Enter) - After Maven finishes creating the project,
cd
into your project folder. - Type
mvn idea:idea
to generate project configuration files for IntelliJ IDEA. - Open IntelliJ IDEA and open the project using File → Open.
Example: a simple greeting service in Camel
In this first example, I’m going to use the camel-jetty component to create a simple web service (HTTP GET) which returns the text “Hello, world!”.
The camel-jetty
component in Apache Camel is a wrapper for Jetty. Jetty is a free, lightweight web server, which makes it ideal for creating a simple web service.
Follow these steps to create your web service using Jetty in Camel:
- Follow the instructions above to create a new Camel project in IntelliJ IDEA. Give the project a suitable name (e.g. JettyGreeting).
- If the Project Tool Window is not visible in IntelliJ, show it by going to View → Tool Windows → Project.
- In the Project Tool Window, double-click the pom.xml file.
-
In the pom.xml editor window, add the following block after the last
dependency
element (before the closing “ tag):<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jetty</artifactId> <version>2.16.2</version> </dependency>
-
In the Project Tool Window, navigate to src/main/java, then into the package you named earlier (e.g. com.example). Then double-click on MyRouteBuilder.java.
-
In the MyRouteBuilder.java editor window, delete the contents of the
configure()
method and replace with the following code:from("jetty://http://localhost:8888/greeting") .log("Received a request") .setBody(simple("Hello, world!"));
Before we run this route, let’s see what we’ve just done:
Modified the pom.xml: We need to add the camel-jetty
component as a dependency in the project’s POM, because Jetty is not included in the standard camel-core
. If you don’t add camel-jetty
as a dependency, Camel will throw the error no component found with scheme: jetty because it cannot find the jetty
component.
Defined a single Camel route using Java DSL: The code in step 6 is important. In one single line of Java, we do the following:
- Tell Camel to use the
jetty
component and start a web server on port 8888, receiving requests at/greeting
. - Add an instruction to write a log every time a request is received.
- Set the response (body) of the service to the simple expression,
"Hello, world!"
. This is done using thesetBody()
methods.
Running the example
Now, to run the example:
-
In IntelliJ IDEA, in the Project Tool Window tree, expand src → main → java → com.example.
-
Right-click on MainApp and choose Run ‘MainApp.main()’ from the context menu.
-
The Camel route will run and the output will be shown in the Console window.
-
Now open your web browser and go to the address
http://localhost:8888/greeting
. -
The text Hello, world! is displayed as the response from your simple web service.
-
Stop the route by returning to IntelliJ IDEA and clicking the red stop button to the left of the Console window, or from the menu bar choose Run → Stop MainApp.
Tip: You can also run the route from the command line by cd
ing to your project folder and typing mvn exec:java
.
Q&A
Q: How does Camel know where to send the “Hello, world!” message?
You may have noticed that the code doesn’t explicitly tell Camel where to send the response message. So how does Camel know to return the “Hello, world!” text back to us, and not pass it somewhere else?
This is because, in Camel, the jetty:
endpoint has a request-reply behaviour by default. This means that it must return a response to the consumer.
In Camel, this request-response behaviour is also known as the InOut message exchange pattern.
If the start component in a route is a request-reply, then once the message has been processed by the route, it will be returned back to the start component.
So, in order to modify the response to the consumer, all we have to do is modify the message body, and the modified message will be returned from the web service.
Example: a simple clock service in Camel
This second example builds on the previous project. It modifies the response from the service to return the current date and time, like a simple clock.
The service above returns a static response. This is not a common use case for web services, and we usually need to return something dynamic to the Consumer.
Using the power of Camel’s Simple language, we can create a simple web service which returns the current date and time.
Simple expressions are very useful in Camel. They allow you to dynamically build a String using placeholders, for example, to insert a value from a message. The placeholders are evaluated at runtime, and the resulting String is returned to the enclosing expression.
In the previous example, the Simple language was used in the expression “Hello, world!”. But this expression contained no placeholders, so the text is always the same.
In this example, we use the Simple language to build a dynamic string. We fetch the current date and time, using the syntax ${date:now:format}
, where format is a Java SimpleDateFormat pattern.
Follow the steps below to create a new web service which returns the current date and time in Camel:
-
Follow the instructions further above to create a new Camel project in IntelliJ IDEA. Give the project a name, e.g.
JettyClock
. -
Follow the steps in the greeting example above to modify your pom.xml to add the
camel-jetty
dependency. -
Modify your main MyRouteBuilder.java file, deleting the contents of the
configure()
method, and replacing with the following code:from("jetty://http://localhost:8889/clock") .log("Received a request") .setBody(simple("${date:now:yyyy-MM-dd'T'HH:mm:ssZ}"));
Running the example
Now run the example:
-
As above, find your project’s MainApp in the Project Tool Window tree, right-click it and choose Run ‘MainApp.main()’ from the context menu.
-
Wait for the the Console window to appear and for the Camel route to finish starting up.
-
Open your web browser and go to the address
http://localhost:8889/clock
. -
The current date and time is returned by the service.
Further learning
Now you’ve seen some basic usage of the Jetty component, why not try using it to:
- serve the contents of a file to a Consumer (e.g. by reading the file using Java and setting this in the body)
- see what happens when you send a POST message to the web service (e.g. by using a web service testing tool such as soapUI)
Comments? Bugs? Feedback? Let me know what you think of this tutorial in the comments below!