The Parallel Universe Blog

January 07, 2015

Using Comsat with Standalone Servlet Containers

By Fabio

We’re going through a tutorial about using Comsat with standalone servlet containers; this post is backed by a Maven archetype for Comsat using Cargo for integration tests.

Quasar brings true lightweight threads or fibers to the JVM. Fibers are similar to (but much cheaper than) traditional threads; they behave just like Erlang processes or Go’s “goroutines” and allow writing straightforward blocking code having the same performance of asynchronous code. In addition to that, Quasar introduces several advanced concurrent programming concepts initially popularized by Erlang and Go, like channels and OTP-like actors, and implements them efficiently using fibers.

Comsat extends Quasar’s benefits to several popular technologies and areas of the JVM ecosystem, like DB access (JDBC, JOOQ, JDBI, MongoDB), ReST-based SOA (JAX-RS server and client) and both the “modern” and “enterprise” Web APIs (Dropwizard and servlets. Support for Spring and Clojure’s Ring Web framework have recently been released as well.

Last but nor least, Comsat also introduces Web Actors, a new actor-based API to deal reliably and uniformly with traditional HTTP request/response cycles as well as Server-Sent Events (SSE) and WebSockets (the Web Spaceships demo is definitely recommended).

Building on Quasar’s powerful integration API, Comsat lends itself equally well to both “modern” Java environments and the still very popular “enterprise” ones which many Companies have invested a lot in; we’re going to take a deeper look at useful Comsat adoption practices in enterprise web development with Tomcat, possibly the most popular standalone servlet container in use today.

Fast bootstrapping with off-the-shelf templates

The following content is backed by a complete and extensively commented Maven archetype that will get you up and running quickly. It includes everything we’re going to cover in this blog post: how to use Tomcat’s custom instrumenting class-loader with Maven, how to do integration testing on most popular Tomcat versions with the excellent Cargo plugin, how to use dependency injection in your code as well as the sample implementations of both plain fiber-blocking servlets and fiber-blocking JAX-RS ReST services.

A simpler Maven archetype for fiber-enabled standalone Java projects with Quasar is also available.

Getting up and running faster with Servlet 3 annotations

The WEB-INF/web.xml descriptor was previously the only way to instruct the servlet container about which servlets and filters had to be instantiated, as well as about how they needed to be setup and mapped to HTTP requests.

Starting with Servlet 3 there are now two more ways to perform the same tasks, both of which rely on code rather than descriptors. Actually, it has even become possible to skip creating a web.xml altogether but some containers may still need one though, albeit basically empty, so it is generally a good idea to always create it:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0"
         metadata-complete="false"> <!-- Will scan libs for servlet annotations as well, default -->
  <display-name>Comsat Web Application</display-name>
</web-app>

The metadata-complete flag is important: if set to true, it will instruct the container to look for annotations only in classes and not in libs. This results in faster startup but can lead to headaches when there are JARs containing annotated filters and servlets that need to be taken into account, as it can be the case with web frameworks, so we’ll be leaving it turned off. As you can see, apart from metadata-complete and display-name, the above descriptor contains no other information.

When writing new servlet and filters, the easiest method is probably using annotation-based configuration through WebServlet and WebFilter, which have attributes mirroring the ones available in web.xml:

@WebServlet(urlPatterns = "/*", asyncSupported = true)
public class TestFiberServlet extends FiberHttpServlet {
    @Suspendable
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // ...
    }
}

Please remember that fiber-blocking servlets must have the asyncSupported attribute set to true, as fiber-blocking support is based on Servlet 3 Async.

Configuring the Comsat-provided JAX-RS fiber-blocking servlet

The web.xml descriptor allows up to setup off-the-shelf pre-packaged servlets, such as the one Comsat provides for fiber-blocking JAX-RS (which is based on Jersey), so we’ll quickly enhance it:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0"
         metadata-complete="false"> <!-- Will scan libs for servlet annotations as well, default -->
    <display-name>Cargo Archetype Web Application Single Module</display-name>

    <!-- Register the fiber-blocking Jersey servlet -->
    <servlet>
        <display-name>fiber</display-name>
        <servlet-name>fiber</servlet-name>
        <!-- Support async (needed by fiber-blocking) -->
        <servlet-class>co.paralleluniverse.fibers.jersey.ServletContainer</servlet-class>
        <async-supported>true</async-supported>
        <!-- Add Jersey configuration class -->
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>testgrp.JerseyApplication</param-value>
        </init-param>
        <!-- Set packages to be scanned for resources -->
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>testgrp</param-value>
        </init-param>
        <!-- Don't lazy-load (fail-fast) -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Mapping -->
    <servlet-mapping>
        <servlet-name>fiber</servlet-name>
        <url-pattern>/fiber-jaxrs/*</url-pattern>
    </servlet-mapping>
</web-app>

The above descriptor configures Comsat’s fiber-blocking Jersey servlet to handle a specific URL pattern, asks for it to be initialized upon container bootstrap, declares it supports Async and configures both an initialization class and the packages to be inspected for annotated classes implementing JAX-RS resources.

Fiber-blocking standard JAX-RS ReST with Comsat’s Jersey integration

Comsat’s support for JAX-RS through its Jersey 2 integration makes it straightforward to implement high-performance, fiber-blocking ReST web services in Java. Just setup the fiber-blocking Jersey servlet as in the previous section and write your ReST resource classes as you would normally do, remembering to declare fiber-blocking methods (including HTTP method handlers) as you would do anywhere else (that is either through the @Suspendable annotation or declaring to throw SuspendExecution):

@Singleton
@Path("/")
public class Resource {
    @Inject
    PersistenceService ps;

    @POST
    @Path("data")
    @Consumes(MediaType.APPLICATION_JSON)
    @Suspendable
    public void store(Data data) throws IOException, InterruptedException, SuspendExecution  {
        ps.store(data);
    }
}

This methods can handle HTTP POST calls and will transparently de-serialize JSON to a new Data instance, which is a straight “plain old Java object” (POJO) annotated with @XmlRootElement from the JAXB 2 standard (which enables XML serialization as well, as you may have guessed):

@XmlRootElement
public class Data {
    String f1;
    String f2;

    /**
     * Default constructor (needed by JAXB/Jackson)
     */
    public Data() {}

    /**
     * Value constructor
     */
    public Data(String f1, String f2) {
        this.f1 = f1;
        this.f2 = f2;
    }

    public String getF2() {
        return f2;
    }

    public String getF1() {
        return f1;
    }
}

JSON support is provided by the utmost popular Jackson JSON toolkit. Jackson too, like dependency injection, is enabled through Jersey’s initialization class, which we’re going to look into next.

Jersey initialization: dependency injection and JSON support

Jersey 2 ships with a Dependency Injection facility based on HK2 but there is a wide array of JSR330 standards-compliant choices; Spring IoC is very flexible and feature-rich, while Dagger is fast and has development-time validation support through an annotation processor.

As shown previously, you can easily declare a dependency to be injected in your JAX-RS resource:

@Singleton
@Path("/")
public class Resource {
    @Inject
    PersistenceService ps;

    // ...
}

You should then define a binder (also known as registry or module elsewhere) that will instruct the dependency injection engine about how to map dependencies to specific implementations:

public class DependencyBinder extends AbstractBinder {
    @Override
    protected void configure() {
       // Replace with your favourite persistence engine impl
       bind(NOPPersistenceServiceImpl.class).to(PersistenceService.class);
    }
}

The registry is made known to Jersey through its initialization class we’ve come across previously, when configuring the web application:

public class JerseyApplication extends ResourceConfig {
    public JerseyApplication() {
        register(new DependencyBinder()); // Support Dependency Injection

        register(JacksonFeature.class);   // Support jackson
    }
}

Here we’re registering the dependency binder so that Jersey can use it for dependency injection in resource classes, then we’re also telling Jersey to enable transparent JSON serialization and de-serialization through Jackson.

Enabling fibers

The JVM doesn’t yet provide native support for fibers but it includes many advanced runtime code management facilities. One such facilities, bytecode instrumentation, makes it possible to transform (and even re-transform) classes’ bytecode arbitrarily before it is executed and opens the door to effectively adding runtime features like fibers.

Quasar’s fiber-enabling instrumentation comes in two flavours:

  • Static or Ahead-of-Time (AoT), which is performed just after compiling classes by an Ant task, or
  • Load-time or agent-based, which is enabled by configuring an Agent for the JVM at launch time.

AoT instrumentation assumes that only project classes need to be instrumented because JARs have already been, so it is not an option with code using libraries that haven’t been AoT-instrumented already.

While agent-based instrumentation is a great choice for standalone applications and embedded servlet containers, in standalone server mode pluggable class loaders are used in order to create private code spaces for individual applications, so a an instrumenting class-loader is needed 1.

Class-loading-based instrumentation requires dropping the appropriate Comsat loader jars in the server’s installation “lib” directory and adding server-specific servlet context configuration descriptors to our web application.

When using Cargo for integration testing, if the appropriate Comsat loader has been declared as a Maven dependency, the first task can be accomplished as easily as adding a dependency element in the plugin’s configuration for Tomcat:

    <profile>
      <id>tomcat8x</id>
      <build>
        <pluginManagement>
          <plugins>
            <plugin>
              <groupId>org.codehaus.cargo</groupId>
              <artifactId>cargo-maven2-plugin</artifactId>
              <configuration>
                <container>
                  <containerId>tomcat8x</containerId>
                  <zipUrlInstaller>
                    <url>http://archive.apache.org/dist/tomcat/tomcat-8/v8.0.15/bin/apache-tomcat-8.0.15.zip</url>
                  </zipUrlInstaller>
                  <dependencies>
                    <dependency>
                      <groupId>co.paralleluniverse</groupId>
                      <artifactId>comsat-tomcat-loader</artifactId>

                      <!-- Use this for JDK 8 -->
                      <classifier>jdk8</classifier>
                    </dependency>
                  </dependencies>
                </container>
              </configuration>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    </profile>

As for the server-specific descriptors, Tomcat’s can be dropped into META-INF/context.xml and can be as simple as:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <!--load the webApp with quasar class loader for insturmentation purposes-->
    <Loader loaderClass="co.paralleluniverse.comsat.tomcat.QuasarWebAppClassLoader" />
</Context>

Advanced: programmatic web application setup

Programmatic configuration is also available through ServletContainerInitializer as an alternative to web.xml:

public class ServletContextSetup implements ServletContainerInitializer {
    @Override
    public void onStartup(Set<Class<?>> set, ServletContext sc) throws ServletException {
        // Register the fiber-blocking Jersey servlet
        javax.servlet.ServletRegistration.Dynamic fiber = sc.addServlet("fiber", co.paralleluniverse.fibers.jersey.ServletContainer.class);

        // Add Jersey configuration class
        fiber.setInitParameter("javax.ws.rs.Application", "testgrp.JerseyApplication");

        // Set packages to be scanned for resources
        fiber.setInitParameter("jersey.config.server.provider.packages", "testgrp");

        // Don't lazy-load (fail-fast)
        fiber.setLoadOnStartup(1);

        // Support async (needed by fiber-blocking)
        fiber.setAsyncSupported(true);

        // Mapping
        fiber.addMapping("/fiber-jaxrs/*");
    }
}

In the snippet above we’re implementing ServletContainerInitializer, which defines only the onStartup method. In this case we’re registering Comsat’s fiber-blocking Jersey servlet and configuring it as explained in comments, similarly to what we’ve done previously through the web.xml descriptor.

The method’s first parameter is meant to allow the definition of multiple initializers, each interested in knowing which classpath classes are there that extend at least some of the types listed by the (optional) HandlesTypes annotation. If there is no such annotation or such classes aren’t found, the initializers will still be invoked but the container will pass null as a first argument value.

ServletContainerInitializer classes are found through the SPI services mechanism rather than annotation-driven classpath scanning, so we need to drop a new META-INF/services/javax.servlet.ServletContainerInitializer resource listing any concrete implementations to be used, one per line:

testgrp.ServletContextSetup

This mechanism certainly has the benefit of avoiding time-consuming classpath sweeps at startup.

Advanced: Comsat and Servlet 3 Async, from thread-based (or callback-based) to fiber-based request serving

The Servlet 3.0 specification introduced the ability to handle requests asynchronously, effectively allowing the container thread assigned to an HTTP request to complete execution without committing the response. Long-running activities can thus be started without keeping expensive threads alive, and can then signal their completion later; only then the HTTP response will be finalised and committed to the server, which will ship it back to the invoking client.

The Servlet API is quite a complex one, was initially designed for synchronous, thread-blocking request processing and has undergone a long compatibility-preserving evolution. Unfortunately there are some grey areas about how the new asynchronous features are supposed to inter-operate with previous APIs and as a result there is a lack of information and it’s not unusual to bump into unexpected behaviors in containers.

Luckily, the basic async API works well at the servlet level and it’s supported by both Jetty (8.1.x and 9.2.x) and Tomcat (7.0.x and 8.0.x).

Here’s a typical asynchronous request serving flow:

  1. At initialisation time, the servlet and all the filters in the requests handling chain are marked as supporting asynchronous mode.
  2. When a new request comes in, the filter chain is traversed and the request finally reaches the mapped servlet.
  3. The servlet puts the request in asynchronous mode through the startAsync call, which returns a new AsyncContext instance.
  4. The servlet starts some asynchronous activity, making the AsyncContext instance available to its callback.
  5. The servlet finishes its handling and the filter chain is traversed back; the HTTP cycle and connection are left “in-progress” though, and no response is returned to the client yet.
  6. At some point later on, the asynchronous activity completes and calls the registered callback, which will invoke a completion method on the AsyncContext. It’ll be one of either:
  • complete, which will commit the response and let the server return it to the client, or
  • dispatch, which will delegate the original request handling to a new, initially synchronous request handling flow (possibly on a different URL, too). This is useful when the asynchronous request handling must be followed by additional server-side processing before being completed; any bookkeeping needed to deal with the outcome of the previous asynchronous processing is left for the application (or framework) logic to implement, as the Servlet specification provides no special support for it.

As seen previously, Quasar makes it very easy to implement fiber-blocking support on top of asynchronous, callback-based APIs: this is precisely how Comsat takes advantage of the Servlet 3 Async feature in order to dispatch request processing to fibers. The FiberHttpServlet class will put the request in async mode and let any HTTP-method-specific logic be executed inside a new fiber, which will finally complete the asynchronous context when it has finished its job. This is the reason why assigning many threads for requests serving can waste resources: they will just put the request in async mode, delegate the actual processing to the fiber pool and complete execution.

This approach allows Comsat to bring the high-performance, yet straightforward fiber-blocking paradigm to servlet-based HTTP request processing. Since it does so through the Servlet Async feature, it also means that Comsat requires a server supporting version 3.0 (or higher) of the Servlet specification (the vast majority nowadays).

Summing it all up

We’ve been through a tour of Comsat’s fiber-blocking JAX-RS support and we have explored servlet container development and standalone deployment options.

Comsat packages together minimal adapters that allow your code to quickly become fiber-blocking while still taking advantage of existing standards and popular tools. Many more of such adapters will be added in the time to come, so stay tuned as Comsat can be an invaluable tool to boost your code assets’ performance, scalability and maintainability with minimal investments.


  1. Remember: a class’ unique ID in a running JVM always includes a reference to its class-loader, so the same class bytecode loaded by two different classloaders will be considered as two distinct classes.

Join our mailing list

Sign up to receive news and updates.

Tags: ,

comments powered by Disqus