java

Configuring Jersey Servlet Container on Embedded Tomcat

One of the ways of configuring a Jersey Servlet Container on Tomcat is via a web.xml file.
For example, typically the following web.xml file is used where a Servlet and its mappings are defined:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>  
<web-app xmlns="http://java.sun.com/xml/ns/javaee"  
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <servlet>
        <servlet-name>API</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>

        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.app.v2.RestApplication</param-value>
        </init-param>

    </servlet>
    <servlet-mapping>
        <servlet-name>API</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>  

When starting an embedded version of Tomcat the same Jersey Servlet that was defined in the XML file can be defined via code:

    RestApplication restApplication = new RestApplication();
    ServletContainer servletContainer = new ServletContainer(restApplication);
    Tomcat.addServlet(ctx, "api", servletContainer);
    ctx.addServletMapping("/api/*", "hubble-api");

There are three steps involved in configuring Jersey:

Tomcat Embedded Server Configuration

Tomcat initially started as a web server container, meaning that one Tomcat server could host several web applications. With the popularity of languages such as Ruby and Node growing and frameworks like rails and express becoming very popular for web applications the new pattern of embedding the web server as part of the application itself removing the need of any external dependencies became very common.
Even though this feature is not very well documented, Tomcat does support an embedded configuration.

Below is an example of converting a standard server.xml to an embedded server.

<?xml version='1.0' encoding='utf-8'?>

<Server port="8010" shutdown="SHUTDOWN">  
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

    <Service name="Catalina">

        <Connector port="8080"
                   protocol="org.apache.coyote.http11.Http11NioProtocol"
                   compression="on"
                   compressableMimeType="application/json"
                   connectionTimeout="5000"
                   maxThreads="50"
                   minSpareThreads="50"
                   redirectPort="9410" />

        <Engine name="Catalina" defaultHost="localhost">

            <Host name="localhost"  appBase="webapps"
                  unpackWARs="true" autoDeploy="false">

            </Host>
        </Engine>
    </Service>

</Server>  

The main components defined in the XML file are:

  • Server
  • Listeners
  • Service
  • Connector
  • Engine
  • Host

When configuring an embedded Tomcat, the xml file listed above can be converted to java code as follows:

Tomcat tomcat = new Tomcat();  
Path tempPath = Files.createTempDirectory("tomcat-base-dir");  
tomcat.setBaseDir(tempPath.toString());

// Configure connector
Connector connector = new Connector();  
connector.setPort(8080);  
connector.setProtocol(Http11NioProtocol.class.getName());  
connector.setProperty("maxThreads", "100");  
connector.setProperty("minSpareThreads", "100");  
connector.setProperty("compression", "on");  
connector.setProperty("compressableMimeType", "application/json");  
connector.setProperty("connectionTimeout", "8000");  
tomcat.getService().addConnector(connector);  
tomcat.setConnector(connector);

// Configure tomcat life cycle listeners
JreMemoryLeakPreventionListener jreMemoryLeakPreventionListener = new JreMemoryLeakPreventionListener();  
GlobalResourcesLifecycleListener globalResourcesLifecycleListener = new GlobalResourcesLifecycleListener();  
ThreadLocalLeakPreventionListener threadLocalLeakPreventionListener = new ThreadLocalLeakPreventionListener();  
VersionLoggerListener versionLoggerListener = new VersionLoggerListener();  
tomcat.getServer().addLifecycleListener(jreMemoryLeakPreventionListener);  
tomcat.getServer().addLifecycleListener(globalResourcesLifecycleListener);  
tomcat.getServer().addLifecycleListener(threadLocalLeakPreventionListener);  
tomcat.getServer().addLifecycleListener(versionLoggerListener);

// Create web context
File webContentFolder = Files.createTempDirectory("default-doc-base").toFile();  
StandardContext ctx = (StandardContext) tomcat.addWebapp("", webContentFolder.getAbsolutePath());

// Disable jar scanner for better start up performance
StandardJarScanFilter jarScanFilter = (StandardJarScanFilter) ctx.getJarScanner().getJarScanFilter();  
jarScanFilter.setTldSkip("*");

tomcat.start();  
tomcat.getServer().await();  

*It is important to set both the default Tomcat connector as well as the service connector the application will use. By default, Tomcat configures an HTTP/1.1 connector listening on port 8080, so if only the service connector is set Tomcat will try to load both connectors at once.

Configuring H2 database for JUnit Tests with OpenJPA

When it comes time to write unit tests for an application most likely then not there will be a scenario where the tests would have to communicate to a database backend. However, using the main database of the application during the unit tests run can pollute and corrupt the data so the recommended approach is to use a dedicated database just for the tests.

Provisioning and maintaining a full database like MySQL or PostgreSQL can have a bit of an overhead. For that regards the most suited database for unit tests is H2

The area where H2 excels is that it can be provisioned before the test suite run starts and at the end removed it since it is a in memory database.

Below are the steps necessary for configuring a OpenJPA Entity Manager Factory using the H2 driver:

Add maven dependency

<dependency>  
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>1.4.191</version>
      <scope>test</scope>
</dependency>  

Create Data Source

PoolConfiguration props = new PoolProperties();  
props.setUsername("test");  
props.setPassword("");  
props.setUrl("jdbc:h2:~/test");  
props.setDriverClassName("org.h2.Driver");  
dataSource = new DataSource();  
dataSource.setPoolProperties(props);  

Create Entity Manager Factory

Properties jpaProps = new Properties();  
jpaProps.put("openjpa.ConnectionFactory", dataSource);  
jpaProps.put("openjpa.Log", "log4j");  
jpaProps.put("openjpa.ConnectionFactoryProperties", "true");  
entityManagerFactory = Persistence.createEntityManagerFactory("myfactory", jpaProps);