Recently I needed to control an embedded web container from a Java application and I wanted to see how this could be achieved using an embedded instance of either Tomcat or Jetty here.

In the following short examples I would like to show how to embed both servers in an application in no time using Gradle or Maven as build tool.

Dependencies

We just need to add the web container libraries to our project here .. I’ve added the build config for Gradle and Maven here…

Gradle

Adding the following instructions to our build.gradle adds everything needed here .. the dependencies for tomcat and jetty and a gradle task to run the application and read user input from STDIN (and other stuff to create project files for Eclipse IDE..)..

apply plugin: 'java'
apply plugin: 'eclipse'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.eclipse.jetty:jetty-server:9.0.0.RC2'
    compile 'org.eclipse.jetty:jetty-servlet:9.0.0.RC2'
    compile 'org.apache.tomcat:tomcat-catalina:7.0.41'
    compile 'org.apache.tomcat:tomcat-util:7.0.41'
    compile 'org.apache.tomcat.embed:tomcat-embed-core:7.0.41'
}

sourceCompatibility = 1.7
targetCompatibility = 1.7

task(selectServer, dependsOn: 'classes', type: JavaExec) {
    main = 'com.hascode.tutorial.app.Main'
    classpath = sourceSets.main.runtimeClasspath
    standardInput= System.in
}

defaultTasks 'selectServer'

Maven

If you prefer Maven, please add the following dependencies to your pom.xml:

<dependencies>
	<dependency>
		<groupId>org.eclipse.jetty</groupId>
		<artifactId>jetty-server</artifactId>
		<version>9.0.0.RC2</version>
	</dependency>
	<dependency>
		<groupId>org.eclipse.jetty</groupId>
		<artifactId>jetty-servlet</artifactId>
		<version>9.0.0.RC2</version>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat</groupId>
		<artifactId>tomcat-catalina</artifactId>
		<version>7.0.41</version>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat</groupId>
		<artifactId>tomcat-util</artifactId>
		<version>7.0.41</version>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-core</artifactId>
		<version>7.0.41</version>
	</dependency>
</dependencies>

Now we’re ready to create a simple web application …

The Application

The main application here allows us to choose the server we want to start by reading our choice from the command line.

Pressing “1″ starts our embedded Jetty server, pressing “2″ starts a Tomcat server….

package com.hascode.tutorial.app;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.catalina.LifecycleException;

import com.hascode.tutorial.container.JettyEmbeddedRunner;
import com.hascode.tutorial.container.TomcatEmbeddedRunner;

public class Main {
	public static void main(final String[] args) throws IOException,
			LifecycleException {
		System.out
				.println("### STARTING EMBEDDED WEB CONTAINER\nPlease select your container...\n1) Jetty\n2) Tomcat\n");
		BufferedReader bufferRead = new BufferedReader(new InputStreamReader(
				System.in));
		String input = bufferRead.readLine();
		if ("1".equals(input)) {
			System.out.println("Starting Jetty ..");
			new JettyEmbeddedRunner().startServer();
		} else if ("2".equals(input)) {
			System.out.println("Starting Tomcat ..");
			new TomcatEmbeddedRunner().startServer();
		} else {
			System.out.println("Nothing selected .. quitting application...");
		}

	}
}

The HTTP Servlet

We’re creating a simple servlet here by extending javax.servlet.http.HttpServlet.

Our servlet simply prints a timestamp to the output stream … that’s all …

package com.hascode.tutorial.servlet;

import java.io.IOException;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DatePrintServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(final HttpServletRequest req,
			final HttpServletResponse res) throws ServletException, IOException {
		res.getWriter()
				.append(String.format("It's %s now\n\n\n\nwww.hascode.com",
						new Date()));
	}
}

Jetty embedded

This is our code to startup an embedded Jetty server instance, running on port 8080 with context-path “app” and our DatePrintServlet registered:

package com.hascode.tutorial.container;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import com.hascode.tutorial.servlet.DatePrintServlet;

public class JettyEmbeddedRunner {
	public void startServer() {
		try {
			Server server = new Server();
			ServerConnector c = new ServerConnector(server);
			c.setIdleTimeout(1000);
			c.setAcceptQueueSize(10);
			c.setPort(8080);
			c.setHost("localhost");
			ServletContextHandler handler = new ServletContextHandler(server,
					"/app", true, false);
			ServletHolder servletHolder = new ServletHolder(
					DatePrintServlet.class);
			handler.addServlet(servletHolder, "/date");
			server.addConnector(c);
			server.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Tomcat embedded

The following lines start a new Tomcat instance, running on port 8080 with context-path “app” and our DatePrintServlet registered, corresponding to the Jetty configuration above.

package com.hascode.tutorial.container;

import java.io.File;

import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;

import com.hascode.tutorial.servlet.DatePrintServlet;

public class TomcatEmbeddedRunner {
	public void startServer() throws LifecycleException {
		Tomcat tomcat = new Tomcat();
		tomcat.setPort(8080);
		File base = new File(System.getProperty("java.io.tmpdir"));
		Context rootCtx = tomcat.addContext("/app", base.getAbsolutePath());
		Tomcat.addServlet(rootCtx, "dateServlet", new DatePrintServlet());
		rootCtx.addServletMapping("/date", "dateServlet");
		tomcat.start();
		tomcat.getServer().await();
	}
}

Directory Structure

This is what my directory structure looks like:

$ tree
.
├── build.gradle
├── README.md
└── src
 └── main
 ├── java
 │   └── com
 │       └── hascode
 │           └── tutorial
 │               ├── app
 │               │   └── Main.java
 │               ├── container
 │               │   ├── JettyEmbeddedRunner.java
 │               │   └── TomcatEmbeddedRunner.java
 │               └── servlet
 │                   └── DatePrintServlet.java
 └── resources

Running the Application

We’re now ready to run our application using the gradle task we’ve defined in the build.gradle.

When typing “1″ or “2″ the application should start either an embedded Jetty or an embedded Tomcat.

Afterwards the web application is accessible by opening the following address in your browser: http://localhost:8080/app/date

$ gradle selectServer
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:selectServer
### STARTING EMBEDDED WEB CONTAINER
Please select your container...
1) Jetty
2) Tomcat

Screenshot

This is what our application looks like in the browser.

running web application
Figure 1. The Date Servlet in the Browser

Tutorial Sources

Please feel free to download the tutorial sources from my GitHub repository, fork it there or clone it using Git:

git clone https://github.com/hascode/webapp-embedded-tutorial.git

Updates

  • 2014-05-24: Maven dependency coordinates fixed, clean shutdown control for Tomcat added (thx @Claude Quézel)

  • 2014-10-12: Typo in build.gradle fixed (thx @Sascha Kratky)