Following on from my previous post where I created a web application in Java, let’s now look at hosting the WAR within an embedded Tomcat instance.
Adding dependencies to include embedded Tomcat
Add the following to your pom.xml (after the description tag)
<properties> <tomcat.version>9.0.0.M6</tomcat.version> </properties>
Note: There’s a newer version of a couple of the dependencies, but this version exists for all three of the dependencies we’re about to add.
Now, add following dependencies
<dependencies> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-logging-juli</artifactId> <version>${tomcat.version}</version> </dependency> </dependencies>
Time to run mvn install if not auto-importing.
Time to create the entry point/application
Let’s add a new package to the src folder, com.putridparrot now add a Java file, mine’s HostApp.java, here’s the code
package com.putridparrot; import org.apache.catalina.LifecycleException; import org.apache.catalina.startup.Tomcat; import javax.servlet.ServletException; import java.io.File; public class HostApp { public static void main(String[] args) throws ServletException, LifecycleException { Tomcat tomcat = new Tomcat(); tomcat.setBaseDir("temp"); tomcat.setPort(8080); String contextPath = ""; String webappDir = new File("web").getAbsolutePath(); tomcat.addWebapp(contextPath, webappDir); tomcat.start(); tomcat.getServer().await(); } }
In the above we create an instance of Tomcat and then set up the port and the context for the web app, including the path to the web folder where our index.jsp is hosted in our WAR file.
We then start the server and then wait until the application is closed.
By the way, it’s also worth adding logging to the pom.xml. The embedded Tomcat server using “standard” Java based logging, so we can add the following to the pom.xml dependencies
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.15</version> </dependency>
Create a run configuration
Now select Edit Configuration and add a configuration that runs main from HostApp.
Adding gzip/compression support, before we start the server. Hence select Application and set Main class to com.putridparrot.HostApp.
Testing
Run the newly added application configuration, don’t worry about the exceptions. You should see a line similar to
INFO: Starting ProtocolHandler [http-nio-8080]
At this point the server is running, so navigate your browser to http://localhost:8080 and check that the index.jsp page is displayed.
Configuring the embedded Tomcat for gzip/compression support
I’ve been looking into compression with gzip on some web code and hence wanted to configure this embedded Tomcat server to handle compression if/when requested via Accept-Type: gzip etc.
So add the following to the main method (before tomcat.start())
Connector c = tomcat.getConnector(); c.setProperty("compression", "on"); c.setProperty("compressionMinSize", "1024"); c.setProperty("noCompressionUserAgents", "gozilla, traviata"); c.setProperty("compressableMimeType", "text/html,text/xml,text/css,application/json,application/javascript"); tomcat.setConnector(c);
You’ll also need the import import org.apache.catalina.connector.Connector;.
Testing gzip/compression
To test whether Tomcat is using compression is best done with something like curl. I say this because, whilst you can use a browser (such as Chrome’s) debug tools and see a response with Content-Type: gzip, I really wanted to see the raw compressed data to feel I really was getting compressed responses, the browser automatically decompressed the responses for me.
Go the main method and just change “on” to “force”
i.e.
c.setProperty("compression", "force");
This just forces compression to be on all the time.
Now to test our server is set up correctly. Thankfully Windows 10 seems to have curl available from a command prompt, so this works in Linux or Windows.
Run the following
curl -H "Accept-Encoding: gzip,deflate" -I "http://localhost:8080/index.jsp"
This command adds the header Accept-Encoding and then outputs the header (-I) results from accessing the URL. This should show a Content-Encoding: gzip if everything was set up correctly.
To confirm everything is as expected, we can download the content from the URL and save it (in this case saved to index.jsp.gz) and then use gzip -d to decompress the file if we wish.
curl -H "Accept-Encoding: gzip,deflate" "http://localhost:8080/index.jsp" -o index.jsp.gz
This will create index.jsp.gz which should be compressed so we can use
gzip -d index.jsp.gz
to decompress it and we should see the expected web page.