Run java web apps in embedded containers with Maven, Jetty and Tomcat


Codever Logo

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ⭐🙏


While developing java web applications is very practical to have quick feedback from a “real” environment. In this post I’ll explore how to run a java web application with Maven in an embedded container be it Jetty or Tomcat.  I’ll show how I have configured them for the development of podcastpedia project backing the Podcastpedia.org website.

Octocat Source code for this post is available on Github - podcastpedia.org is an open source project.

Prerequisites

You should have Maven and  at least Java 7 installed. Ideally you could setup up the podcastpedia project yourself to see it in action.

Jetty Maven Plugin

<!-- https://www.eclipse.org/jetty/documentation/current/jetty-maven-plugin.html -->
<plugin>
	<groupId>org.eclipse.jetty</groupId>
	<artifactId>jetty-maven-plugin</artifactId>
	<version>${jetty.version}</version>
	<configuration>
		<jettyConfig>${project.basedir}/src/main/resources/config/jetty9.xml</jettyConfig>
		<stopKey>STOP</stopKey>
		<stopPort>9999</stopPort>
		<scanIntervalSeconds>5</scanIntervalSeconds>
		<scanTargets>
			<scanTarget>${project.basedir}/src/main</scanTarget>
			<scanTarget>${project.basedir}/src/test</scanTarget>
		</scanTargets>
		<contextXml>${project.basedir}/src/test/resources/jetty-context.xml</contextXml>
		<webAppConfig>
			<contextPath>/</contextPath>
		</webAppConfig>
	</configuration>
	<dependencies>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.connector.java.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>${java.mail.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-jdbc</artifactId>
			<version>${tomcat.jdbc.version}</version>
		</dependency>
	</dependencies>
</plugin>

Notes:

  • jettyConfig points to the Jetty configuration file; see next section for more explanations
  • defined folders (scanTargets) where Jetty looks for changes every 5 seconds (scanInterval)
  • defined external dependencies to connect to database and send email

Jetty.xml configuration file

<?xml version="1.0" encoding="UTF-8"?>
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
	<New id="pcmdbDS" class="org.eclipse.jetty.plus.jndi.Resource">
		<Arg>jdbc/pcmDB</Arg>
		<Arg>
			<New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
				<Set name="Url">jdbc:mysql://localhost:3307/pcmDB?allowMultiQueries=true
				</Set>
				<Set name="User">pcm</Set>
				<Set name="Password">pcm_pw</Set>
			</New>
		</Arg>
	</New>
	<New id="mailSessionId" class="org.eclipse.jetty.plus.jndi.Resource">
		<Arg>mail/Session</Arg>
		<Arg>
			<New class="org.eclipse.jetty.jndi.factories.MailSessionReference">
				<Set name="user">test-dev@podcastpedia.org</Set>
				<Set name="password">test-dev</Set>
				<Set name="properties">
					<New class="java.util.Properties">
						<Put name="mail.host">mail.podcastpedia.org</Put>
						<Put name="mail.debug">true</Put>
						<Put name="mail.transport.protocol">smtp</Put>
						<Put name="mail.smtp.port">25</Put>
						<Put name="mail.smtp.auth">true</Put>
					</New>
				</Set>
			</New>
		</Arg>
	</New>
</Configure>

In the Jetty configuration file (jetty.xml) you have the following configured:

  • The Server class (or subclass if extended) and global options.
  • A ThreadPool (min and max thread).
  • Connectors (ports, timeouts, buffer sizes, protocol).
  • The handler structure (default handlers and/or a contextHandlerCollections).
  • The deployment manager that scans for and deploys webapps and contexts.
  • Login services that provide authentication checking.
  • A request log.

Apache Tomcat Maven Plugin

<!-- https://tomcat.apache.org/maven-plugin-trunk/index.html -->
<plugin>
	<groupId>org.apache.tomcat.maven</groupId>
	<artifactId>tomcat7-maven-plugin</artifactId>
	<version>2.2</version>
	<configuration>
		<!-- http port -->
		<port>8080</port>
		<!-- application path always starts with /-->
		<path>/</path>
		<!-- optional path to a context file -->
		<contextFile>context.xml</contextFile>
		<!-- optional system propoerties you want to add -->
		<systemProperties>
			<appserver.base>${project.build.directory}/appserver-base</appserver.base>
			<appserver.home>${project.build.directory}/appserver-home</appserver.home>
			<derby.system.home>${project.build.directory}/appserver-base/logs</derby.system.home>
			<java.io.tmpdir>${project.build.directory}</java.io.tmpdir>
		</systemProperties>
		<!-- if you want to use test dependencies rather than only runtime -->
		<useTestClasspath>false</useTestClasspath>
		<!-- optional if you want to add some extra directories into the classloader -->
		<additionalClasspathDirs>
			<additionalClasspathDir></additionalClasspathDir>
		</additionalClasspathDirs>
	</configuration>
	<!-- For any extra dependencies needed when running embedded Tomcat (not WAR dependencies) add them below -->
	<dependencies>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.connector.java.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>${java.mail.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-jdbc</artifactId>
			<version>${tomcat.jdbc.version}</version>
		</dependency>
	</dependencies>
</plugin>

Notes

  • specify port where Tomcat runs
  • specify contextFile where Tomcat looks for configuration
  • defined external dependencies to connect to database and send email

Context.xml

<Context>
  <Resource
            name="jdbc/pcmDB"
            auth="Container"
            type="javax.sql.DataSource"
            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
            initialSize="5"
            maxActive="55"
            maxIdle="21"
            minIdle="13"
            timeBetweenEvictionRunsMillis="34000"
            minEvictableIdleTimeMillis="55000"
            validationQuery="SELECT 1"
            validationInterval="34"
            testOnBorrow="true"
            removeAbandoned="true"
            removeAbandonedTimeout="233"
            username="pcm"
            password="pcm_pw"
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3307/pcmDB?allowMultiQueries=true"
   />

	<Resource name="mail/Session" auth="Container"
	            type="javax.mail.Session"
		        username="test-dev@podcastpedia.org"
		        password="test-dev"
	            mail.smtp.host="mail.podcastpedia.org"
	            mail.smtp.port="25"
	            mail.smtp.user="test-dev@podcastpedia.org"
	            mail.transport.protocol="smtp"
	            mail.smtp.auth="true"
	/>
</Context>

In context.xml there are defined the database and email resources.

Note:
These are simple configurations, but suffice for current development. My advice is to read the corresponding documentation for more advanced options and capabilities.


There you go… Java webapps powered by Spring Framework running light servlet containers posing a true alternative to JAVA EE servers and all the costs that come with them.

Octocat Source code for this post is available on Github - podcastpedia.org is an open source project.

References

  1. Jetty Maven Plugin
  2. Apache Tomcat Maven Plugin
Podcastpedia image

Adrian Matei

Creator of Podcastpedia.org and Codepedia.org, computer science engineer, husband, father, curious and passionate about science, computers, software, education, economics, social equity, philosophy - but these are just outside labels and not that important, deep inside we are all just consciousness, right?
Subscribe to our newsletter for more code resources and news

Adrian Matei (aka adixchen)

Adrian Matei (aka adixchen)
Life force expressing itself as a coding capable human being

routerLink with query params in Angular html template

routerLink with query params in Angular html template code snippet Continue reading