OLD JETTY DOCUMENTATION

The Jetty documentation that follows refers to old Jetty versions, and it is currently being ported to the current Jetty version.

Please be patient if you find incorrect documentation for the current Jetty version: eventually, the old documentation will be ported to the current Jetty version and it will be up to date.

Application Layer Protocol Negotiation (ALPN)

The development of new web protocols such as HTTP/2 raised the need of protocol negotiation within a Transport Layer Security (TLS) handshake. A protocol negotiation called ALPN (Application Layer Protocol Negotiation - RFC7301) has been defined to accomplish this.

ALPN has now replaced the older (and now fully deprecated) NPN in the general Web as of 2016.

For those browsers that support HTTP/2, they all now support ALPN. Starting with Jetty 9.3.0, only ALPN is supported by Jetty.

Introducing ALPN

Application Layer Protocol Negotiation (ALPN) is a TLS extension that allows client and server to negotiate the application protocol that they will use to communicate within the encryption provided by TLS.

Any protocol can be negotiated by ALPN within a TLS connection; the protocols that are most commonly negotiated are HTTP/2 and HTTP/1.1.

Browsers only support HTTP/2 over TLS by negotiating the HTTP/2 protocol via ALPN. You need to configure the server to support TLS and ALPN if you want browsers to use the HTTP/2 protocol, otherwise they will default to HTTP/1.1.

In the Jetty project, ALPN is used in two artifacts: jetty-alpn-client and jetty-alpn-server, respectively for the client and for the server.

When using Jetty as a standalone server via the Jetty distribution, the jetty-alpn-server artifact is automatically included in the server classpath by the Jetty module system.

When using Jetty embedded, the jetty-alpn-client and jetty-alpn-server artifacts must be included in the classpath, respectively for client and server use cases.

The ALPN implementation is provided to these two artifacts with the following three options:

  • For JDK 8 or later, a provider based on the Conscrypt security provider

    • Works with JDK 8 or later and provides improved performance

    • Binds to the OpenSSL native library shipped by Conscrypt and is therefore only available on the platforms supported by Conscrypt

  • For JDK 9 or later, a provider based on the ALPN APIs present in the JDK

    • Works with JDK 9 or later, pure Java implementation

    • Lower performance than Conscrypt

The first, although hosted under the umbrella of the Jetty project, is independent of Jetty (the Servlet Container); you can use it in any other Java network server.

Each provider above provides an ALPN service implementation; Jetty uses the ServiceLoader mechanism to load these service implementations. At least one valid provider must be present in the server classpath. For example, using JDK 8 with the JDK 9 ALPN provider is an invalid combination. The absence of valid implementations is an error at startup (see also the troubleshooting section).

There may be multiple ALPN service providers in the server classpath. When a new connection is created, an SSLEngine instance is associated to it; each SSLEngine is passed all service implementations, until one accepts it.

It is therefore possible to have multiple providers active at the same time, for example the JDK 9 provider and the Conscrypt provider, and at runtime the correct one will be chosen by the Jetty runtime.

ALPN and Conscrypt

When using JDK 8 or later, you can use the Conscrypt security provider to provide the ALPN service implementation.

Conscrypt binds natively to BoringSSL (a fork of OpenSSL by Google), so ALPN will be supported via the support provided by BoringSSL (bundled together with Conscrypt).

When using Jetty as a standalone server via the Jetty distribution, ALPN is enabled by enabling the conscrypt module.

When using Jetty embedded, ALPN is enabled by the jetty-alpn-conscrypt-client and jetty-alpn-conscrypt-server artifacts, respectively for client usage and server usage. In addition, you also need the Conscrypt artifacts, typically the org.conscrypt:conscrypt-openjdk-uber artifact. All these artifacts must be added to the classpath.

ALPN and JDK 9

When using JDK 9 or later and Jetty as a standalone server via the Jetty distribution, ALPN support is automatically enabled when the http2 module is enabled. This enables transitively the alpn-9 module which puts the jetty-alpn-java-server artifact in the server classpath, providing the ALPN JDK 9 service implementation.

When using JDK 9 or later and Jetty embedded, the ALPN service implementation is provided by the jetty-alpn-java-client and jetty-alpn-java-server artifacts, respectively for client usage and server usage, and must be added to the classpath.

Starting in OSGi

To use ALPN in an OSGi environment, in addition to what described above, you will also need to deploy the jetty-osgi-alpn jar. This jar contains a Fragment-Host directive that ensures the ALPN classes will be available from the system bundle.

You can download the jetty-osgi-alpn jar from Maven Central.

OSGi requires a ServiceLoader implementation for Jetty to function properly. OSGi leverages Apache Aries SPI Fly for this functionality. You can read more about OSGi and ServiceLoader here.

ALPN Troubleshooting

When starting the Jetty server, especially when using Jetty embedded, it may be possible that you see an error similar to this:

IllegalStateException: no ALPN processor

The error means that you don’t have the ALPN dependencies setup correctly in your classpath.

For example, you do not have the jetty-alpn-java-server artifact in the classpath.

Annotations

Jetty supports the servlet specification annotations. It is not enable by default, so the following sections show you how to enable it, and how to use them.

Quick Setup

Jetty Distribution

If you are using the jetty distribution, then annotations are enabled by default. The annotations module and its transitive dependencies are responsible for making annotation processing available.

Note that annotations that relate to JNDI, such as @Resource and @Resources are enabled via the JNDI module, which is a transitive dependency on the annotations module.

Jetty Maven Plugin

Annotations and JNDI are pre-enabled for the Maven plugin.

Embedding

To use annotations in an embedded scenario, you will need to include the jetty-annotations jar and all its dependencies onto your classpath. You will also need to include the org.eclipse.jetty.annotations.AnnotationConfiguration class into the list of Configuration classes applied to the org.eclipse.jetty.ee9.webapp.WebAppContext class representing your webapp.

Below is an example application that sets up the standard test-spec.war webapp from the distribution in embedded fashion. It can also be found in the Jetty GitHub repository on the examples/embedded page as ServerWithAnnotations.java. Note that the test-spec.war uses not only annotations, but also JNDI, so this example also enables their processing (via the org.eclipse.jetty.plus.webapp.EnvConfiguration, org.eclipse.jetty.plus.webapp.PlusConfiguration and their related jars).

Unresolved directive in annotations/quick-annotations-setup.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithAnnotations.java[]

Unresolved directive in annotations/chapter.adoc - include::using-annotations.adoc[]

Using Annotations with Jetty Embedded

Setting up the Classpath

You will need to place the following Jetty jar files onto the classpath of your application. You can obtain them from the Jetty distribution, or the Maven repository:

jetty-plus.jar
jetty-annotations.jar

You will also need the asm jar, which you can obtain from this link.

Example

Here’s an example application that sets up a Jetty server, performs some setup to ensure that annotations are scanned, and then deploys a webapp that uses annotations. This example also uses the @Resource annotation which involves JNDI, so we would also add the necessary JNDI jars to the classpath. The example also adds in the configuration classes that are responsible for JNDI (see line 19).

The code is as follows:

import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.ee9.webapp.WebAppContext;

/**
 * ServerWithAnnotations
 *
 *
 */
public class ServerWithAnnotations
{
    public static final void main(String args[]) throws Exception
    {
        //Create the server
        Server server = new Server(8080);

        //Enable parsing of jndi-related parts of web.xml and jetty-env.xml
        org.eclipse.jetty.ee9.webapp.Configuration.ClassList classlist = org.eclipse.jetty.ee9.webapp.Configuration.ClassList.setServerDefault(server);
        classlist.addAfter("org.eclipse.jetty.ee9.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration");
        classlist.addBefore("org.eclipse.jetty.ee9.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.annotations.AnnotationConfiguration");

        //Create a WebApp
        WebAppContext webapp = new WebAppContext();
        webapp.setContextPath("/");
        webapp.setWar("../../tests/test-webapps/test-servlet-spec/test-spec-webapp/target/test-spec-webapp-9.0.4-SNAPSHOT.war");
        server.setHandler(webapp);

        //Register new transaction manager in JNDI
        //At runtime, the webapp accesses this as java:comp/UserTransaction
        org.eclipse.jetty.plus.jndi.Transaction transactionMgr = new org.eclipse.jetty.plus.jndi.Transaction(new com.acme.MockUserTransaction());

        //Define an env entry with webapp scope.
        org.eclipse.jetty.plus.jndi.EnvEntry maxAmount = new org.eclipse.jetty.plus.jndi.EnvEntry (webapp, "maxAmount", new Double(100), true);


        // Register a  mock DataSource scoped to the webapp
        org.eclipse.jetty.plus.jndi.Resource mydatasource = new org.eclipse.jetty.plus.jndi.Resource(webapp, "jdbc/mydatasource", new com.acme.MockDataSource());

        // Configure a LoginService
        HashLoginService loginService = new HashLoginService();
        loginService.setName("Test Realm");
        loginService.setConfig("src/test/resources/realm.properties");
        server.addBean(loginService);


        server.start();
        server.join();
    }

}

On line 19 the configuration classes responsible for setting up JNDI and java:comp/env are added.

On line 20 we add in the configuration class that ensures annotations are inspected.

On lines 30, 33 and 37 JNDI resources that we will be able to reference with @Resource annotations are configured.

With the setup above, a servlet that uses annotations and Jetty will honour the annotations when the webapp is deployed can be created:

import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RunAs;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.annotation.WebInitParam;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import javax.transaction.UserTransaction;

/**
 * AnnotationTest
 *
 * Use servlet 3.0 annotations from within Jetty.
 *
 * Also uses servlet 2.5 resource injection and lifecycle callbacks
 */

@RunAs("special")
@WebServlet(urlPatterns = {"/","/test/*"}, name="AnnotationTest", initParams={@WebInitParam(name="fromAnnotation", value="xyz")})
@DeclareRoles({"user","client"})
public class AnnotationTest extends HttpServlet
{
    private DataSource myDS;

    @Resource(mappedName="UserTransaction")
    private UserTransaction myUserTransaction;

    @Resource(mappedName="maxAmount")
    private Double maxAmount;


    @Resource(mappedName="jdbc/mydatasource")
    public void setMyDatasource(DataSource ds)
    {
        myDS=ds;
    }


    @PostConstruct
    private void myPostConstructMethod ()
    {
        System.err.println("PostConstruct called");
    }


    @PreDestroy
    private void myPreDestroyMethod()
    {
        System.err.println("PreDestroy called");
    }

    public void init(ServletConfig config) throws ServletException
    {
        super.init(config);
    }


    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        doGet(request, response);
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        try
        {
            response.setContentType("text/html");
            ServletOutputStream out = response.getOutputStream();
            out.println("<html>");
            out.println("<body>");
            out.println("<h1>Results</h1>");
            out.println(myDS.toString());
            out.println("<br/>");
            out.println(maxAmount.toString());
            out.println("</body>");
            out.println("</html>");
            out.flush();
        }
        catch (Exception e)
        {
            throw new ServletException(e);
        }
    }
}

Architecture

General items related to the architecture of jetty and how it deals with certain design decisions.

Jetty Classloading

Class loading in a web container is slightly more complex than a normal Java application. The normal configuration is that each web context (web application or WAR file) has its own classloader, which has the system classloader as its parent. Such a classloader hierarchy is normal in Java, however the servlet specification complicates the hierarchy because it requires the following:

  • Classes contained within WEB-INF/lib or WEB-INF/classes have priority over classes on the parent classloader. This is the opposite of the normal behavior of a Java 2 classloader.

  • System classes such as java.lang.String are excluded from the webapp priority, and you may not replace them with classes in WEB-INF/lib or WEB-INF/ classes. Unfortunately the specification does not clearly state what classes are System classes, and it is unclear if all javax classes should be treated as System classes.

  • Server implementation classes like Server should be hidden from the web application and should not be available in any classloader. Unfortunately the specification does not state what classes are Server classes, and it is unclear if common libraries like the Xerces parser should be treated as Implementation classes.

Configuring Webapp Classloading

Jetty provides configuration options to control the three webapp class loading issues identified above.

You can configure webapp classloading by several methods on the WebAppContext. You can call these methods directly if you are working with the Jetty API, or you can inject methods from a context XML file if you are using the Context Provider ([using-context-provider]). You CANNOT set these methods from a jetty-web.xml file, as it executes after the classloader configuration is set. As a note, jetty-web.xml uses the webapp classpath and not the classpath of the server.

Controlling Webapp Classloader Priority

The method org.eclipse.jett .webapp.WebAppContext.setParentLoaderPriority(boolean) allows control over the priority given to webapp classes over system classes. If you set it to false (the default), Jetty uses standard webapp classloading priority. However, if in this mode some classes that are dependencies of other classes are loaded from the parent classloader (due to settings of system classes below), ambiguities might arise as both the webapp and system classloader versions can end up being loaded.

If set to true, Jetty uses normal JavaSE classloading priority, and gives priority to the parent/system classloader. This avoids the issues of multiple versions of a class within a webapp, but the version the parent/system loader provides must be the right version for all webapps you configure in this way.

Configuring Webapp Classloader Caching

Introduced in Jetty 9.3.6, the CachingWebAppClassLoader can be used to cache getResource(String) results. For webapps that search for classes and resources regularly, this can increase speed and performance. This is an optional feature and it should be noted that it can conflict with several other libraries such as JSP, JSTL, JSF and CDI. As such, this feature must be manually enabled for each webapp you want to use it in.

Below is an example of implementing this feature using Jetty IoC XML format:

<Configure id="mywebapp" class="org.eclipse.jetty.ee9.webapp.WebAppContext">

...

  <Set name="classLoader">
    <New class="org.eclipse.jetty.ee9.webapp.CachingWebAppClassLoader">
      <Arg><Ref refid="mywebapp"/></Arg>
    </New>
  </Set>

...
</Configure>
Setting System Classes

You can call the methods WebAppContext.setSystemClasses(String[]) or WebAppContext.getSystemClasspathPattern().add(String) to allow fine control over which classes are considered system classes.

  • A web application can see a System class.

  • A WEB-INF class cannot replace a System class.

The default system classes are:

Table 1. Default System Classes
System Classes Note

java.

Java SE classes (per servlet spec v2.5 / SRV.9.7.2).

javax.

Java SE classes (per servlet spec v2.5 / SRV.9.7.2).

org.xml.

Needed by javax.xml.

org.w3c.

Needed by javax.xml.

org.eclipse.jetty.continuation.

Webapp can see and not change continuation classes.

org.eclipse.jetty.jndi.

Webapp can see and not change naming classes.

org.eclipse.jetty.jaas.

Webapp can see and not change JAAS classes.

org.eclipse.jetty.websocket.

WebSocket is a Jetty extension.

org.eclipse.jetty.ee9.servlet.DefaultServlet

Webapp can see and not change default servlet.

Absolute classname can be passed, names ending with . are treated as packages names, and names starting with - are treated as negative matches and must be listed before any enclosing packages.

Setting Server Classes

You can call the methods org.eclipse.jetty.ee9.webapp.WebAppContext.setServerClasses(String Array) or org.eclipse.jetty.ee9.webapp.WebAppContext.addServerClass(String) to allow fine control over which classes are considered Server classes.

  • A web application cannot see a Server class.

  • A WEB-INF class can replace a Server class.

The default server classes are:

Table 2. Default Server Classes
Server Classes -org.eclipse.jetty.continuation.

Don’t hide continuation classes.

-org.eclipse.jetty.jndi.

Don’t hide naming classes.

-org.eclipse.jetty.jaas.

Don’t hide jaas classes.

-org.eclipse.jetty.ee9.servlets.

Don’t hide utility servlet classes if provided.

-org.eclipse.jetty.ee9.servlet.DefaultServlet

Don’t hide default servlet.

-org.eclipse.jetty.ee9.servlet.listener.

Don’t hide utility listeners

-org.eclipse.jetty.websocket.

Don’t hide websocket extension.

org.eclipse.jetty.

Adding Extra Classpaths to Jetty

You can add extra classpaths to Jetty in several ways.

Using start.jar

If you are using start.jar via the Jetty distribution, at startup the Jetty runtime automatically loads option Jars from the top level $jetty.home/lib directory. The default settings include:

  • Adding Jars under $jetty.home/lib/ext to the system classpath. You can place additional Jars here.

  • Adding the directory $jetty.home/resources to the classpath (may contain classes or other resources).

  • Adding a single path defined by the command line parameter path.

Using the extraClasspath() method

You can add an additional classpath to a context classloader by calling org.eclipse.jetty.ee9.webapp.WebAppContext.setExtraClasspath(String) with a comma-separated list of paths. You can do so directly to the API via a context XML file such as the following:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
 ...
 <Set name="extraClasspath">../my/classes,../my/jars/special.jar,../my/jars/other.jar</Set>
 ...

Using a Custom WebAppClassLoader

If none of the alternatives already described meet your needs, you can always provide a custom classloader for your webapp. We recommend, but do not require, that your custom loader subclasses WebAppClassLoader.

If you do not subclass WebAppClassLoader, we recommend that you implement the ClassVisibilityChecker interface. Without this interface, session persistence will be slower.

You configure the classloader for the webapp like so:

MyCleverClassLoader myCleverClassLoader = new MyCleverClassLoader();
 ...
   WebAppContext webapp = new WebAppContext();
 ...
   webapp.setClassLoader(myCleverClassLoader);

You can also accomplish this in a context xml file.

Starting Jetty with a Custom ClassLoader

If you start a Jetty server using a custom class loader–consider the Jetty classes not being available to the system class loader, only your custom class loader–you may run into class loading issues when the WebAppClassLoader kicks in. By default the WebAppClassLoader uses the system class loader as its parent, hence the problem. This is easy to fix, like so:

context.setClassLoader(new WebAppClassLoader(this.getClass().getClassLoader(), context));

or

context.setClassLoader(new WebAppClassLoader(new MyCustomClassLoader(), context));

Configuring Jetty Connectors

This chapter discusses various options for configuring Jetty connectors.

Connector Configuration Overview

Connectors are the mechanism through which Jetty accepts network connections for various protocols. Configuring a connector is a combination of configuring the following:

  • Network parameters on the connector itself (for example: the listening port).

  • Services the connector uses (for example: executors, schedulers).

  • Connection factories that instantiate and configure the protocol for an accepted connection.

Typically connectors require very little configuration aside from setting the listening port, and enabling X-Forwarded-For customization when applicable. Additional settings, including construction your own constructor Jetty XML files, are for expert configuration only.

Enabling Connectors

Out of the box, Jetty provides several modules for enabling different types of connectors, from HTTP to HTTPS, HTTP/2, and others. If you startup Jetty with the --list-modules=connector command, you can see a list of all available connector modules:

[my-base]$ java -jar /path/to/jetty-home/start.jar --list-modules=connector

Available Modules:
==================
tags: [connector]

Modules for tag 'connector':
----------------------------

     Module: acceptratelimit
           : Enable a server wide accept rate limit
       Tags: connector
     Depend: server
        XML: etc/jetty-acceptratelimit.xml

     Module: connectionlimit
           : Enable a server wide connection limit
       Tags: connector
     Depend: server
        XML: etc/jetty-connectionlimit.xml

     Module: http
           : Enables a HTTP connector on the server.
           : By default HTTP/1 is support, but HTTP2C can
           : be added to the connector with the http2c module.
       Tags: connector, http
     Depend: server
        XML: etc/jetty-http.xml

     Module: http-forwarded
           : Adds a forwarded request customizer to the HTTP Connector
           : to process forwarded-for style headers from a proxy.
       Tags: connector
     Depend: http
        XML: etc/jetty-http-forwarded.xml

     Module: http2
           : Enables HTTP2 protocol support on the TLS(SSL) Connector,
           : using the ALPN extension to select which protocol to use.
       Tags: connector, http2, http, ssl
     Depend: ssl, alpn
        LIB: lib/http2/*.jar
        XML: etc/jetty-http2.xml

     Module: http2c
           : Enables the HTTP2C protocol on the HTTP Connector
           : The connector will accept both HTTP/1 and HTTP/2 connections.
       Tags: connector, http2, http
     Depend: http
        LIB: lib/http2/*.jar
        XML: etc/jetty-http2c.xml

     Module: https
           : Adds HTTPS protocol support to the TLS(SSL) Connector
       Tags: connector, https, http, ssl
     Depend: ssl
   Optional: http-forwarded, http2
        XML: etc/jetty-https.xml

     Module: proxy-protocol-ssl
           : Enables the Proxy Protocol on the TLS(SSL) Connector.
           : http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
           : This allows a Proxy operating in TCP mode to transport
           : details of the proxied connection to the server.
           : Both V1 and V2 versions of the protocol are supported.
       Tags: connector, ssl
     Depend: ssl
        XML: etc/jetty-proxy-protocol-ssl.xml

     Module: ssl
           : Enables a TLS(SSL) Connector on the server.
           : This may be used for HTTPS and/or HTTP2 by enabling
           : the associated support modules.
       Tags: connector, ssl
     Depend: server
        XML: etc/jetty-ssl.xml
        XML: etc/jetty-ssl-context.xml

     Module: unixsocket
           : Enables a Unix Domain Socket Connector that can receive
           : requests from a local proxy and/or SSL offloader (eg haproxy) in either
           : HTTP or TCP mode.  Unix Domain Sockets are more efficient than
           : localhost TCP/IP connections  as they reduce data copies, avoid
           : needless fragmentation and have better dispatch behaviours.
           : When enabled with corresponding support modules, the connector can
           : accept HTTP, HTTPS or HTTP2C traffic.
       Tags: connector
     Depend: server
        LIB: lib/jetty-unixsocket-${jetty.version}.jar
        LIB: lib/jnr/*.jar
        XML: etc/jetty-unixsocket.xml

     Module: unixsocket-forwarded
           : Adds a forwarded request customizer to the HTTP configuration used
           : by the Unix Domain Socket connector, for use when behind a proxy operating
           : in HTTP mode that adds forwarded-for style HTTP headers. Typically this
           : is an alternate to the Proxy Protocol used mostly for TCP mode.
       Tags: connector
     Depend: unixsocket-http
        XML: etc/jetty-unixsocket-forwarded.xml

     Module: unixsocket-http
           : Adds a HTTP protocol support to the Unix Domain Socket connector.
           : It should be used when a proxy is forwarding either HTTP or decrypted
           : HTTPS traffic to the connector and may be used with the
           : unix-socket-http2c modules to upgrade to HTTP/2.
       Tags: connector, http
     Depend: unixsocket
        XML: etc/jetty-unixsocket-http.xml

     Module: unixsocket-http2c
           : Adds a HTTP2C connetion factory to the Unix Domain Socket Connector
           : It can be used when either the proxy forwards direct
           : HTTP/2C (unecrypted) or decrypted HTTP/2 traffic.
       Tags: connector, http2
     Depend: unixsocket-http
        LIB: lib/http2/*.jar
        XML: etc/jetty-unixsocket-http2c.xml

     Module: unixsocket-proxy-protocol
           : Enables the proxy protocol on the Unix Domain Socket Connector
           : http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
           : This allows information about the proxied connection to be
           : efficiently forwarded as the connection is accepted.
           : Both V1 and V2 versions of the protocol are supported and any
           : SSL properties may be interpreted by the unixsocket-secure
           : module to indicate secure HTTPS traffic. Typically this
           : is an alternate to the forwarded module.
       Tags: connector
     Depend: unixsocket
        XML: etc/jetty-unixsocket-proxy-protocol.xml

     Module: unixsocket-secure
           : Enable a secure request customizer on the HTTP Configuration
           : used by the Unix Domain Socket Connector.
           : This looks for a secure scheme transported either by the
           : unixsocket-forwarded, unixsocket-proxy-protocol or in a
           : HTTP2 request.
       Tags: connector
     Depend: unixsocket-http
        XML: etc/jetty-unixsocket-secure.xml
...

To enable a connector, simply activate the associated module. Below is an example of activating both the http and https modules in a fresh Jetty base using the start.d directory:

[mybase] java -jar $JETTY_HOME/start.jar --create-startd
MKDIR : ${jetty.base}/start.d
INFO  : Base directory was modified

[mybase] java -jar $JETTY_HOME/start.jar --add-to-start=http,https
INFO  : server          transitively enabled, ini template available with --add-to-start=server
INFO  : http            initialized in ${jetty.base}/start.d/http.ini
INFO  : https           initialized in ${jetty.base}/start.d/https.ini
INFO  : ssl             transitively enabled, ini template available with --add-to-start=ssl
MKDIR : ${jetty.base}/etc
COPY  : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
INFO  : Base directory was modified
[mybase] tree
.
├── etc
│   └── keystore
└── start.d
    ├── http.ini
    └── https.ini

When the http and https modules were activated, so too were any modules they were dependent on, in this case server and ssl, as well as any dependencies for those modules, such as the etc and ketystore directories for ssl.

At this point the server has been configured with connectors for both HTTP and HTTPS and can be started:

[mybase] java -jar $JETTY_HOME/start.jar
2017-08-31 10:19:58.855:INFO::main: Logging initialized @372ms to org.eclipse.jetty.util.log.StdErrLog
2017-08-31 10:19:59.076:INFO:oejs.Server:main: jetty-12.0.9-SNAPSHOT
2017-08-31 10:19:59.125:INFO:oejs.AbstractConnector:main: Started ServerConnector@421e98e0{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2017-08-31 10:19:59.150:INFO:oejus.SslContextFactory:main: x509=X509@5315b42e(jetty,h=[jetty.eclipse.org],w=[]) for SslContextFactory@2ef9b8bc(file:///var/my-jetty-base/etc/keystore,file:///var/my-jetty-base/etc/keystore)
2017-08-31 10:19:59.151:INFO:oejus.SslContextFactory:main: x509=X509@5d624da6(mykey,h=[],w=[]) for SslContextFactory@2ef9b8bc(file:///var/my-jetty-base/etc/keystore,file:///var/my-jetty-base/etc/keystore)
2017-08-31 10:19:59.273:INFO:oejs.AbstractConnector:main: Started ServerConnector@2b98378d{SSL,[ssl, http/1.1]}{0.0.0.0:8443}
2017-08-31 10:19:59.274:INFO:oejs.Server:main: Started @791ms

When modules are enabled, they are loaded with several default options. These can be changed by editing the associated module ini file in the start.d directory (or the associated lines in server.ini if your implementation does not use start.d). For example, if we examine the http.ini file in our start.d directory created above, we will see the following settings:

# ---------------------------------------
# Module: http
# Enables a HTTP connector on the server.
# By default HTTP/1 is support, but HTTP2C can
# be added to the connector with the http2c module.
# ---------------------------------------
--module=http

### HTTP Connector Configuration

## Connector host/address to bind to
# jetty.http.host=0.0.0.0

## Connector port to listen on
# jetty.http.port=8080

## Connector idle timeout in milliseconds
# jetty.http.idleTimeout=30000

## Number of acceptors (-1 picks default based on number of cores)
# jetty.http.acceptors=-1

## Number of selectors (-1 picks default based on number of cores)
# jetty.http.selectors=-1

## ServerSocketChannel backlog (0 picks platform default)
# jetty.http.acceptQueueSize=0

## Thread priority delta to give to acceptor threads
# jetty.http.acceptorPriorityDelta=0

## HTTP Compliance: RFC7230, RFC2616, LEGACY
# jetty.http.compliance=RFC7230

To make a change to these settings, uncomment the line (by removing the #) and change the property to the desired value. For example, if you wanted to change the HTTP port to 5231, you would edit the line as follows:

...
## Connector port to listen on
jetty.http.port=5231
...

Now when the server is started, HTTP connections will enter on port 5231:

[my-base]$ java -jar /path/to/jetty-home/start.jar
2017-08-31 10:31:32.955:INFO::main: Logging initialized @366ms to org.eclipse.jetty.util.log.StdErrLog
2017-08-31 10:31:33.109:INFO:oejs.Server:main: jetty-12.0.9-SNAPSHOT
2017-08-31 10:31:33.146:INFO:oejs.AbstractConnector:main: Started ServerConnector@2ef9b8bc{HTTP/1.1,[http/1.1]}{0.0.0.0:5231}
...
2017-08-31 10:31:33.263:INFO:oejs.Server:main: Started @675ms

Every module has their own set of configuration options, and reviewing them all is recommended. For additional information on the module system, please refer to our documentation on Startup Modules.

Editing these module files is the recommended way to edit the configuration of your server. Making changes to the associated Jetty XML file for connectors is not recommended, and is for advanced users only. If you do wish to edit Jetty XML, please see our section on managing Jetty Home and Jetty Base to ensure your Jetty Home remains a standard of truth for your implementation.

Limiting Connections

Jetty also provides the means by which to limit connections to the server and/or contexts. This is provided by two different modules in the distribution.

connectionlimit

Applies a limit to the number of connections. If this limit is exceeded, new connections are suspended for the time specified (in milliseconds).

acceptratelimit

Limits the rate at which new connections are accepted. If this limit is exceeded, new connections are suspended for the time specified (in milliseconds).

As with the modules listed above, these can be enabled by adding --add-to-start=<module-name> to the command line.

Advanced Configuration

Jetty primarily uses a single connector type called ServerConnector.

Prior to Jetty 9, the type of the connector specified both the protocol and the implementation used; for example, selector-based non blocking I/O vs blocking I/O, or SSL connector vs non-SSL connector. Jetty 9 has a single selector-based non-blocking I/O connector, and a collection of ConnectionFactories now configure the protocol on the connector.

The standard Jetty distribution comes with the following Jetty XML files that create and configure connectors; you should examine them as you read this section:

jetty-http.xml

Instantiates a ServerConnector that accepts HTTP connections (that may be upgraded to WebSocket connections).

jetty-ssl.xml

Instantiates a ServerConnector that accepts SSL/TLS connections. On it’s own, this connector is not functional and requires one or more of the following files to also be configured to add ConnectionFactories to make the connector functional.

jetty-https.xml

Adds a HttpConnectionFactory to the ServerConnector configured by jetty-ssl.xml which combine to provide support for HTTPS.

jetty-http-forwarded.xml

Adds a ForwardedRequestCustomizerto the HTTP Connector to process forwarded-for style headers from a proxy.

jetty-http2.xml

Adds a Http2ServerConnectionFactory to the ServerConnector configured by jetty-ssl.xml to support the http2 protocol.

jetty-alpn.xml

Adds an ALPNServerConnectionFactory to the ServerConnector configured by jetty-ssl.xml which allows the one SSL connector to support multiple protocols with the ALPN extension used to select the protocol to be used for each connection.

Constructing a ServerConnector

The services a ServerConnector instance uses are set by constructor injection and once instantiated cannot be changed. Many of the services may be defaulted with null or 0 values so that a reasonable default is used, thus for most purposes only the Server and the connection factories need to be passed to the connector constructor. In Jetty XML (that is, in jetty-http.xml) you can do this by:

<New class="org.eclipse.jetty.server.ServerConnector">
  <Arg name="server"><Ref refid="Server" /></Arg>
  <Arg name="factories">
    <Array type="org.eclipse.jetty.server.ConnectionFactory">
      <!-- insert one or more factories here -->
    </Array>
  </Arg>
  <!-- set connector fields here -->
</New>

You can see the other arguments that can be passed when constructing a ServerConnector in the Javadoc. Typically the defaults are sufficient for almost all deployments.

Network Settings

You can configure connector network settings by calling setters on the connector before it is started. For example, you can set the port with the Jetty XML:

<New class="org.eclipse.jetty.server.ServerConnector">
  <Arg name="server"><Ref refid="Server" /></Arg>
  <Arg name="factories"><!-- insert one or more factories here --></Arg>

  <Set name="port">8080</Set>
</New>

Values in Jetty XML can also be parameterized so that they may be passed from property files or set on the command line. Thus typically the port is set within Jetty XML, but uses the Property element to be customizable:

<New class="org.eclipse.jetty.server.ServerConnector">
  <Arg name="server"><Ref refid="Server" /></Arg>
  <Arg name="factories"><!-- insert one or more factories here --></Arg>

  <Set name="port"><Property name="jetty.http.port" default="8080"/></Set>
</New>

The network settings available for configuration on the ServerConnector include:

Table 3. Connector Configuration
Field Description

host

The network interface this connector binds to as an IP address or a hostname. If null or 0.0.0.0, bind to all interfaces.

port

The configured port for the connector or 0 a random available port may be used (selected port available via getLocalPort()).

idleTimeout

The time in milliseconds that the connection can be idle before it is closed.

defaultProtocol

The name of the default protocol used to select a ConnectionFactory instance. This defaults to the first ConnectionFactory added to the connector.

stopTimeout

The time in milliseconds to wait before gently stopping a connector.

acceptQueueSize

The size of the pending connection backlog. The exact interpretation is JVM and operating system specific and you can ignore it. Higher values allow more connections to wait pending an acceptor thread. Because the exact interpretation is deployment dependent, it is best to keep this value as the default unless there is a specific connection issue for a specific OS that you need to address.

reuseAddress

Allow the server socket to be rebound even if in TIME_WAIT. For servers it is typically OK to leave this as the default true.

HTTP Configuration

The HttpConfiguration class holds the configuration for HttpChannels, which you can create 1:1 with each HTTP connection or 1:n on a multiplexed HTTP/2 connection. Thus a HttpConfiguration object is injected into both the HTTP and HTTP/2 connection factories. To avoid duplicate configuration, the standard Jetty distribution creates the common HttpConfiguration instance in jetty.xml, which is a Ref element then used in jetty-http.xml, jetty-https.xml and in jetty-http2.xml.

A typical configuration of HttpConfiguration is:

<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
  <Set name="secureScheme">https</Set>
  <Set name="securePort"><Property name="jetty.ssl.port" default="8443" /></Set>
  <Set name="outputBufferSize">32768</Set>
  <Set name="requestHeaderSize">8192</Set>
  <Set name="responseHeaderSize">8192</Set>
</New>

This example HttpConfiguration may be used by reference to the ID “httpConfig”:

<Call name="addConnector">
  <Arg>
    <New class="org.eclipse.jetty.server.ServerConnector">
      <Arg name="server"><Ref refid="Server" /></Arg>
      <Arg name="factories">
        <Array type="org.eclipse.jetty.server.ConnectionFactory">
          <Item>
            <New class="org.eclipse.jetty.server.HttpConnectionFactory">
              <Arg name="config"><Ref refid="httpConfig" /></Arg>
            </New>
          </Item>
        </Array>
      </Arg>
      <!-- ... -->
    </New>
  </Arg>
</Call>

This same httpConfig is referenced by the SecuredRedirectHandler when redirecting secure requests. Please note that if your httpConfig does not include a secureScheme or securePort or there is no HttpConfiguration present these types of secured requests will be returned a 403 error.

For SSL-based connectors (in jetty-https.xml and jetty-http2.xml), the common “httpConfig” instance is used as the basis to create an SSL specific configuration with ID “sslHttpConfig”:

<New id="sslHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
  <Arg><Ref refid="httpConfig"/></Arg>
  <Call name="addCustomizer">
    <Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
  </Call>
</New>

This adds a SecureRequestCustomizer which adds SSL Session IDs and certificate information as request attributes.

SSL Context Configuration

The SSL/TLS connectors for HTTPS and HTTP/2 require a certificate to establish a secure connection. Jetty holds certificates in standard JVM keystores and are configured as keystore and truststores on a SslContextFactory.Server instance that is injected into an SslConnectionFactory instance. An example using the keystore distributed with Jetty (containing a self signed test certificate) is in jetty-https.xml. Read more about SSL keystores in Configuring SSL.

Proxy / Load Balancer Connection Configuration

Often a Connector needs to be configured to accept connections from an intermediary such as a Reverse Proxy and/or Load Balancer deployed in front of the server. In such environments, the TCP/IP connection terminating on the server does not originate from the client, but from the intermediary, so that the Remote IP and port number can be reported incorrectly in logs and in some circumstances the incorrect server address and port may be used.

Thus Intermediaries typically implement one of several de facto standards to communicate to the server information about the original client connection terminating on the intermediary. Jetty supports the X-Forwarded-For header and the Proxy Protocol mechanisms as described below.

The XML files in the Jetty distribution contain commented out examples of both the X-Forwarded-For and Proxy Protocol mechanisms. When using those examples, it is recommended that the XML in the Jetty distribution is not edited. Rather the files should be copied into a Jetty base directory and then modified.
X-Forward-for Configuration

The X-Forwarded-for header and associated headers are a de facto standard where intermediaries add HTTP headers to each request they forward to describe the originating connection. These headers can be interpreted by an instance of ForwardedRequestCustomizer which can be added to a HttpConfiguration as follows:

<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
  <Set name="outputBufferSize">32768</Set>
  <Set name="requestHeaderSize">8192</Set>
  <Set name="responseHeaderSize">8192</Set>

  <Call name="addCustomizer">
    <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
  </Call>
</New>
Proxy Protocol

The Proxy Protocol is the de facto standard created by HAProxy and used by environments such as Amazon Elastic Cloud. This mechanism is independent of any protocol, so it can be used for HTTP2, TLS etc. The information about the client connection is sent as a small data frame on each newly established connection. In Jetty, this protocol can be handled by the ProxyConnectionFactory which parses the data frame and then instantiates the next ConnectionFactory on the connection with an end point that has been customized with the data obtained about the original client connection. The connection factory can be added to any ServerConnector and should be the first ConnectionFactory.

An example of adding the factory to a HTTP connector is shown below:

<Call name="addConnector">
  <Arg>
    <New class="org.eclipse.jetty.server.ServerConnector">
      <Arg name="server"><Ref refid="Server" /></Arg>
      <Arg name="factories">
        <Array type="org.eclipse.jetty.server.ConnectionFactory">
          <Item>
            <New class="org.eclipse.jetty.server.ProxyConnectionFactory"/>
          </Item>
          <Item>
            <New class="org.eclipse.jetty.server.HttpConnectionFactory">
              <Arg name="config"><Ref refid="httpConfig" /></Arg>
            </New>
          </Item>
        </Array>
      </Arg>
      <Set name="host"><Property name="jetty.host" /></Set>
      <Set name="port"><Property name="jetty.http.port" default="80" /></Set>
    </New>
  </Arg>
</Call>

Configuring Contexts

This chapter discusses various options for configuring Jetty contexts.

Setting a Context Path

The context path is the prefix of a URL path that is used to select the context(s) to which an incoming request is passed. Typically a URL in a Java servlet server is of the format http://hostname.com/contextPath/servletPath/pathInfo, where each of the path elements can be zero or more / separated elements. If there is no context path, the context is referred to as the root context. The root context must be configured as / but is reported as the empty string by the servlet API getContextPath() method.

How you set the context path depends on how you deploy the web application (or ContextHandler).

Using Embedded Deployment

If you run Jetty from code as an embedded server (see Embedding), setting the context path is a matter of calling the setContextPath method on the ContextHandler instance (or WebAppContext instance).

By naming convention

If a web application is deployed using the WebAppProvider of the DeploymentManager without an XML IoC file, then the name of the WAR file is used to set the context path:

  • If the WAR file is named myapp.war, then the context will be deployed with a context path of /myapp

  • If the WAR file is named ROOT.WAR (or any case insensitive variation), then the context will be deployed with a context path of /

  • If the WAR file is named ROOT-foobar.war ( or any case insensitive variation), then the context will be deployed with a context path of / and a virtual host of "foobar"

By Deployer configuration

If a web application is deployed using the WebAppProvider of the DeploymentManager with an XML IoC file to configure the context, then the setContextPath method can be called within that file. For example:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/test</Set>
  ...
</Configure>

Embedding a WEB-INF/jetty-web.xml File

You can also set the context path for webapps by embedding a WEB-INF/jetty-web.xml file in the WAR, which uses the same XML IoC format as the deployer example above. However this is not the preferred method as it requires the web application to be modified.

Temporary Directories

Jetty itself has no temporary directories, but you can assign a directory for each web application, into which the WAR is unpacked, JSPs compiled on-the-fly, etc. If you do not assign a specific temporary directory, Jetty will create one as needed when your web application starts. Whether you set the location of the temporary directory - or you let Jetty create one for you - you also have a choice to either keep or delete the temporary directory when the web application stops.

The Default Temp Directory

By default, Jetty will create a temporary directory for each web application. The name of the directory will be of the form:

"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"+randomdigits+".dir"

For example:

jetty-0.0.0.0-8080-test.war-_test-any-8900275691885214790.dir

Where 0.0.0.0 is the host address, 8080 is the port, test.war is the resourceBase, test is the context path (with / converted to _), any is the virtual host, and randomdigits are a string of digits guaranteed to be unique.

Once the temp directory is created, it is retrievable as the value (as a File) of the context attribute jakarta.servlet.context.tempdir.

The location of the temp directory

By default, Jetty will create this directory inside the directory named by the java.io.tmpdir System property. You can instruct Jetty to use a different parent directory by setting the context attribute org.eclipse.jetty.ee9.webapp.basetempdir to the name of the desired parent directory. The directory named by this attribute must exist and be writeable.

As usual with Jetty, you can either set this attribute in a context xml file, or you can do it in code.

Here’s an example of setting it in an xml file:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">

  <Set name="contextPath">/test</Set>
  <Set name="war">foo.war</Set>

  <Call name="setAttribute">
    <Arg>org.eclipse.jetty.ee9.webapp.basetempdir</Arg>
    <Arg>/home/my/foo</Arg>
  </Call>
</Configure>

The equivalent in code is:

WebAppContext context = new WebAppContext();
context.setContextPath("/test");
context.setWar("foo.war");
context.setAttribute("org.eclipse.jetty.ee9.webapp.basetempdir", "/tmp/foo");

Setting a Specific Temp Directory

There are several ways to use a particular directory as the temporary directory:

Call WebAppContext.setTempDirectory(String dir)

As before this can be accomplished with an XML file or directly in code. Here is an example of setting the temp directory in XML:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">

  <Set name="contextPath">/test</Set>
  <Set name="war">foo.war</Set>

  <Set name="tempDirectory">/some/dir/foo</Set>
</Configure>

And here is an example of doing it with java code:

WebAppContext context = new WebAppContext();
context.setContextPath("/test");
context.setWar("foo.war");
context.setTempDirectory(new File("/some/dir/foo"));
Setting the jakarta.servlet.context.tempdir Context Attribute

You should set this context attribute with the name of directory you want to use as the temp directory. Again, you can do this in XML:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">

  <Set name="contextPath">/test</Set>
  <Set name="war">foo.war</Set>

  <Call name="setAttribute">
    <Arg>jakarta.servlet.context.tempdir</Arg>
    <Arg>/some/dir/foo</Arg>
  </Call>

</Configure>

Or in java:

WebAppContext context = new WebAppContext();
context.setContextPath("/test");
context.setWar("foo.war");
context.setAttribute("jakarta.servlet.context.tempdir", "/some/dir/foo");

Once a temporary directory has been created by either of these methods, a file instance for it is set as the value of the jakarta.servlet.context.tempdir attribute of the web application.

Be wary of setting an explicit temp directory if you are likely to change the jars in WEB-INF/lib between redeployments. There is a JVM bug concerning caching of jar contents.
Setting the Temp Directory on the Command Line

You can set the location of the temp directory on the command line when Jetty starts up in two ways. First is the most straightforward, simply add it to your command line when starting Jetty.

[my-base]$ java -jar /path/to/jetty-home/start.jar -Djava.io.tmpdir=/path/to/desired/directory

Alternately, this can be defined in a module. The jvm module packaged with Jetty is set up to add additional JVM options. After enabling the module (using the --add-to-start=jvm command), edit the jvm.ini file and add the location to the temporary directory. You will also need verify the line including the --exec command is not commented out, as this is required for Jetty to start a new, forked JVM. Below is an example of the standard jvm.ini file altered to include a reference to a temp directory.

# ---------------------------------------
# Module: jvm
# A noop module that creates an ini template useful for
# setting JVM arguments (eg -Xmx )
# ---------------------------------------
--module=jvm

## JVM Configuration
## If JVM args are include in an ini file then --exec is needed
## to start a new JVM from start.jar with the extra args.
##
## If you wish to avoid an extra JVM running, place JVM args
## on the normal command line and do not use --exec
--exec
# -Xmx2000m
# -Xmn512m
# -XX:+UseConcMarkSweepGC
# -XX:ParallelCMSThreads=2
# -XX:+CMSClassUnloadingEnabled
# -XX:+UseCMSCompactAtFullCollection
# -XX:CMSInitiatingOccupancyFraction=80
# -internal:gc
# -XX:+PrintGCDateStamps
# -XX:+PrintGCTimeStamps
# -XX:+PrintGCDetails
# -XX:+PrintTenuringDistribution
# -XX:+PrintCommandLineFlags
# -XX:+DisableExplicitGC
-Djava.io.tmpdir=/path/to/desired/directory

The "work" Directory

It is possible to create a directory named work in the $\{jetty.base} directory. If such a directory is found, it is assumed you want to use it as the parent directory for all of the temporary directories of the webapps in $\{jetty.base}. Moreover, as has historically been the case, these temp directories inside the work directory are not cleaned up when Jetty exits (or more correctly speaking, the temp directory corresponding to a context is not cleaned up when that context stops).

When a work directory is used, the algorithm for generating the name of the context-specific temp directories omits the random digit string. This ensures the name of the directory remains consistent across context restarts.

Persisting the temp directory

Sometimes it is useful to keep the contents of the temporary directory between restarts of the web application. By default, Jetty will not persist the temp directory. To configure Jetty to keep it, use WebAppContext.setPersistTempDirectory(true).

Be aware that if you call setPersistTempDirectory(true), but let Jetty create a new temp directory each time (i.e. you do NOT set an explicit temp directory), then you will accumulate temp directories in your chosen temp directory location.

Creating Custom Error Pages

The following sections describe several ways to create custom error pages in Jetty.

Defining error pages in web.xml

You can use the standard webapp configuration file located in webapp/WEB-INF/web.xml to map errors to specific URLs with the error-page element. This element creates a mapping between the error-code or exception-type to the location of a resource in the web application.

  • error-code - an integer value

  • exception-type - a fully qualified class name of a Java Exception type

  • location - location of the resource in the webapp relative to the root of the web application. Value should start with /.

Error code example:

<error-page>
  <error-code>404</error-code>
  <location>/jspsnoop/ERROR/404</location>
</error-page>

Exception example:

<error-page>
  <exception-type>java.io.IOException</exception-type>
  <location>/jspsnoop/IOException</location>
</error-page>

The error page mappings created with the error-page element will redirect to a normal URL within the web application and will be handled as a normal request to that location and thus may be static content, a JSP or a filter and/or servlet. When handling a request generated by an error redirection, the following request attributes are set and are available to generate dynamic content:

jakarta.servlet.error.exception

The exception instance that caused the error (or null).

jakarta.servlet.error.exception_type

The class name of the exception instance that caused the error (or null).

jakarta.servlet.error.message

The error message.

jakarta.servlet.error.request_uri

The URI of the request with an error.

jakarta.servlet.error.servlet_name

The Servlet name of the servlet that the request was dispatched to.

jakarta.servlet.error.status_code

The status code of the error (e.g. 404, 500 etc.).

Configuring error pages context files

You can use context IoC XML files to configure the default error page mappings with more flexibility than is available with web.xml, specifically with the support of error code ranges. Context files are normally located in ${jetty.base}/webapps/ (see DeployerManager for more details) and an example of more flexible error page mapping is below:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/test</Set>
  <Set name="war">
    <SystemProperty name="jetty.base" default="."/>/webapps/test
  </Set>

  <!-- by Code -->
  <Get name="errorHandler">
    <Call name="addErrorPage">
      <Arg type="int">404</Arg>
      <Arg type="String">/jspsnoop/ERROR/404</Arg>
    </Call>
  </Get>

  <!-- by Exception -->
  <Get name="errorHandler">
    <Call name="addErrorPage">
      <Arg>
        <Call class="java.lang.Class" name="forName">
          <Arg type="String">java.io.IOException</Arg>
        </Call>
      </Arg>
      <Arg type="String">/jspsnoop/IOException</Arg>
    </Call>
  </Get>

  <!-- by Code Range -->
  <Get name="errorHandler">
    <Call name="addErrorPage">
      <Arg type="int">500</Arg>
      <Arg type="int">599</Arg>
      <Arg type="String">/dump/errorCodeRangeMapping</Arg>
    </Call>
  </Get>
</Configure>

Custom ErrorHandler class

If no error page mapping is defined, or if the error page resource itself has an error, then the error page will be generated by an instance of ErrorProcessor configured either the Context or the Server. An ErrorProcessor may extend the ErrorProcessor class and may totally replace the handle method to generate an error page, or it can implement some or all of the following methods to partially modify the error pages:

void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message) throws IOException
void writeErrorPage(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks) throws IOException
void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message) throws IOException
void writeErrorPageBody(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks) throws IOException
void writeErrorPageMessage(HttpServletRequest request, Writer writer, int code, String message, String uri) throws IOException
void writeErrorPageStacks(HttpServletRequest request, Writer writer) throws IOException

An ErrorProcessor instance may be set on a Context by calling the ContextHandler.setErrorHandler method. This can be done by embedded code or via context IoC XML. For example:

<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
  ...
  <Set name="errorHandler">
    <New class="com.acme.handler.MyErrorHandler"/>
  </Set>
  ...
</Configure>

An ErrorProcessor instance may be set on the entire server by setting it as a dependent bean on the Server instance. This can be done by calling Server.addBean(Object) via embedded code or in jetty.xml IoC XML:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  ...
  <Call name="addBean">
    <Arg>
      <New class="com.acme.handler.MyErrorHandler"/>
    </Arg>
  </Call>
  ...
</Configure>

Server level 404 error

It is possible to get a 'page not found' when a request is made to the server for a resource that is outside of any registered contexts. As an example, you have a domain name pointing to your public server IP, yet no context is registered with Jetty to serve pages for that domain. As a consequence, the server, by default, gives a listing of all contexts running on the server.

One of the quickest ways to avoid this behavior is to create a catch all context. Create a "root" web app mapped to the "/" URI, and use the index.html redirect to whatever place with a header directive.

Setting Max Form Size

When a client issues a POST request with Content-Type: application/x-www-form-urlencoded there are 2 configurable limits imposed to help protect the server against denial of service attacks by malicious clients sending huge amounts of data.

There is a maximum form size limit, and a maximum form keys limit.

The default maximum form size Jetty permits is 200000 bytes. The default maximum form keys Jetty permits is 1000 keys.

You can change these defaults for a particular webapp, or all webapps within the same JVM.

For a Single Webapp

The methods to invoke are:

  • ContextHandler.setMaxFormContentSize(int maxSize);

  • ContextHandler.setMaxFormKeys(int max);

This can be done either in a context XML deployment descriptor external to the webapp, or in a jetty-web.xml file in the webapp’s WEB-INF directory.

In either case the syntax of the XML file is the same:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
  <!-- Max Form Size                                                   -->
  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
  <Set name="maxFormContentSize">400000</Set>
  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
  <!-- Max Form Keys                                                   -->
  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
  <Set name="maxFormKeys">400</Set>
</Configure>

For All Apps in the JVM

Use the system properties:

  • org.eclipse.jetty.server.Request.maxFormContentSize - the maximum size of Form Content allowed

  • org.eclipse.jetty.server.Request.maxFormKeys - the maximum number of Form Keys allowed

This can be set on the command line or in the $JETTY_BASE\start.ini or any $JETTY_BASE\start.d\*.ini module ini file. Using $JETTY_BASE\start.d\server.ini as an example:

# ---------------------------------------
# Module: server
# Enables the core Jetty server on the classpath.
# ---------------------------------------
--module=server

### Common HTTP configuration
## Scheme to use to build URIs for secure redirects
# jetty.httpConfig.secureScheme=https

...

-Dorg.eclipse.jetty.server.Request.maxFormContentSize=400000
-Dorg.eclipse.jetty.server.Request.maxFormKeys=400

Deploying to Jetty

This chapter discusses various ways to deploy applications with Jetty. Topics range from deployment bindings to deploying third party products. It also includes information about the Deployment Manager and WebApp Provider.

Configuring a Specific Web Application Deployment

Using the Automatic Web Application Deployment model is quick and easy, but sometimes you might need to tune certain deployment properties (for example, you want to deploy with a context path that is not based on the file name, or you want to define a special database connection pool just for this web application). You can use a Jetty Deployable Descriptor XML File to accomplish such tuning.

Jetty Deployable Descriptor XML File

Jetty supports deploying Web Applications via XML files which will build an instance of a ContextHandler that Jetty can then deploy.

Using Basic Descriptor Files

In a default Jetty installation, Jetty scans its $JETTY_HOME/webapps directory for context deployment descriptor files. To deploy a web application using such a file, simply place the file in that directory.

The deployment descriptor file itself is an xml file that configures a WebAppContext class. For a basic installation only two properties need configured:

war

The filesystem path to the web application file (or directory)

contextPath

The context path to use for the web application

For example, here is a descriptor file that deploys the file /opt/myapp/myapp.war to the context path /wiki:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/wiki</Set>
  <Set name="war">/opt/myapp/myapp.war</Set>
</Configure>

Both SystemProperty and Property elements can be used in the descriptor file. For example, if the system property is set to myapp.home=/opt/myapp, the previous example can be rewritten as:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/wiki</Set>
  <Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
</Configure>

If the home path for an application needs altered, only the system property needs changed. This is useful if the version of an app is frequently changed.

To ensure your web.xml files are validated, you will need to set the validateXml attribute to true as described here.

Configuring Advanced Descriptor Files

Official documentation for the for the WebAppContext class lists all the properties that can be set. Here are some examples that configure advanced options in the descriptor file.

This first example tells Jetty not to expand the WAR file when deploying it. This can help make it clear that users should not make changes to the temporary unpacked WAR because such changes do not persist, and therefore do not apply the next time the web application deploys.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/wiki</Set>
  <Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
  <Set name="extractWAR">false</Set>
</Configure>

The next example retrieves the JavaEE Servlet context and sets an initialization parameter on it. The setAttribute method can also be used to set a Servlet context attribute. However, since the web.xml for the web application is processed after the deployment descriptor, the web.xml values overwrite identically named attributes from the deployment descriptor.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/wiki</Set>
  <Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
  <Get name="ServletContext">
     <Call name="setInitParameter">
       <Arg>myapp.config</Arg>
       <Arg><SystemProperty name="myapp.home">/config/app-config.xml</Arg>
    </Call>
  </Get>
</Configure>

The following example sets a special web.xml override descriptor. This descriptor is processed after the web application’s web.xml, so it may override identically named attributes. This feature is useful when adding parameters or additional Servlet mappings without breaking open a packed WAR file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/wiki</Set>
  <Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
  <Set name="overrideDescriptor">/opt/myapp/overlay-web.xml</Set>
</Configure>

The next example configures not only the web application context, but also a database connection pool (see Datasource Examples) that the application can then use. If the web.xml does not include a reference to this data source, an override descriptor mechanism (as shown in the previous example) can be used to include it.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/wiki</Set>
  <Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg></Arg>
    <Arg>jdbc/DSTest</Arg>
    <Arg>
      <New class="org.apache.commons.dbcp.BasicDataSource">
        <Set name="driverClassName">org.some.Driver</Set>
        <Set name="url">jdbc.url</Set>
        <Set name="username">jdbc.user</Set>
        <Set name="password">jdbc.pass</Set>
      </New>
    </Arg>
  </New>
</Configure>

There are many other settings that can be changed in a WebAppContext. The javadoc for WebAppContext is a good source of information. Also see the documentation on avoiding zip file exceptions for a description of WebAppContext settings that determine such things as whether or not the war is automatically unpacked during deployment, or whether certain sections of a webapp are copied to a temporary location.

Deployment Processing of WebAppContexts

Web applications require a certain amount of processing before they can go into service: they may need to be unpacked, a special classloader created for their jar files, web.xml and web-fragment.xml descriptors processed, and classes scanned for annotations amongst other things. As web applications have become more complex, Jetty has added ways to assist with customization by either broadening or lessening the amount of processing that is done at deployment time. This section will examine this processing and it can be tailored to fit individual needs.

If instead you’re looking for information on how to configure a specific WebAppContext - such as its context path, whether it should be unpacked or not - then you can find that in the section entitled Configuring a Specific WebApp Deployment.

Configuration Classes

As a webapp is being deployed, a series of org.eclipse.jetty.ee9.webapp.Configuration classes are applied to it, each one performing a specific function. The ordering of these Configurations is significant as subsequent Configurations tend to build on information extracted or setup in foregoing Configurations. These are the default list, in order, of Configurations that are applied to each org.eclipse.jetty.ee9.webapp.WebAppContext:

Table 4. Default Configuration classes

org.eclipse.jetty.ee9.webapp.WebInfConfiguration

Extracts war, orders jars and defines classpath

org.eclipse.jetty.ee9.webapp.WebXmlConfiguration

Processes a WEB-INF/web.xml file

org.eclipse.jetty.ee9.webapp.MetaInfConfiguration

Looks in container and webapp jars for META-INF/resources and META-INF/web-fragment.xml

org.eclipse.jetty.ee9.webapp.FragmentConfiguration

Processes all discovered META-INF/web-fragment.xml files

org.eclipse.jetty.ee9.webapp.JettyWebXmlConfiguration

Processes a WEB-INF/jetty-web.xml file

Anatomy of a Configuration Class

A Configuration class is called 5 times in different phases of the WebAppContext’s lifecycle:

preConfigure

As the WebAppContext is starting up this phase is executed. The Configuration should discover any of the resources it will need during the subsequent phases.

configure

This phase is where the work of the class is done, usually using the resources discovered during the preConfigure phase.

postConfigure

This phase allows the Configuration to clear down any resources that may have been created during the previous 2 phases that are not needed for the lifetime of the WebAppContext.

deconfigure

This phase occurs whenever a WebAppContext is being stopped and allows the Configuration to undo any resources/metadata that it created. A WebAppContext should be able to be cleanly start/stopped multiple times without resources being held.

destroy

This phase is called when a WebAppContext is actually removed from service. For example, the war file associated with it is deleted from the $JETTY_HOME/webapps directory.

Each phase is called on each Configuration class in the order in which the Configuration class is listed. Using the default Configuration classes as an example, preConfigure() will be called on WebInfConfiguration, WebXmlConfiguration, MetaInfConfiguration, FragmentConfiguration and then JettyWebXmlConfiguration. The cycle begins again for the configure() phase and again for the postConfigure() phases. The cycle is repeated in reverse order for the deconfigure() and eventually the destroy() phases.

Extending Container Support by Creating Extra Configurations

As shown, there is a default set of Configurations that support basic deployment of a webapp. JavaEE features such as JNDI and advanced servlet spec features such as annotations have not been mentioned. Jetty’s philosophy is to allow the user to tailor the container exactly to their needs. If these features are not needed, then Jetty does not pay the price for them - an important consideration because features such as annotations require extensive and time-consuming scanning of WEB-INF/lib jars. As modern webapps may have scores of these jars, it can be a source of significant deployment delay. We will see in the section Other Configuration another helpful webapp facility that Jetty provides for cutting down the time spent analyzing jars.

Jetty makes use of the flexibility of Configurations to make JNDI and annotation support pluggable.

Firstly, lets look at how Configurations help enable JNDI.

Example: JNDI Configurations

JNDI lookups within web applications require the container to hookup resources defined in the container’s environment to that of the web application. To achieve that, we use 2 extra Configurations:

Table 5. JNDI Configuration classes

org.eclipse.jetty.plus.webapp.EnvConfiguration

Creates java:comp/env for the webapp, applies a WEB-INF/jetty-env.xml file

org.eclipse.jetty.plus.webapp.PlusConfiguration

Processes JNDI related aspects of WEB-INF/web.xml and hooks up naming entries

These configurations must be added in exactly the order shown above and should be inserted immediately before the org.eclipse.jetty.ee9.webapp.JettyWebXmlConfiguration class in the list of configurations. To fully support JNDI additional configuration is required, full details of which can be found here.

Example: Annotation Configurations

We need just one extra Configuration class to help provide servlet annotation scanning:

Table 6. Annotation Configuration classes

org.eclipse.jetty.annotations.AnnotationConfiguration

Scan container and web app jars looking for @WebServlet, @WebFilter, @WebListener etc

The above configuration class must be inserted immediately before the org.eclipse.jetty.ee9.webapp.JettyWebXmlConfiguration class in the list of configurations. To fully support annotations additional configuration is require, details of which can be found below.

How to Set the List of Configurations

You have a number of options for how to make Jetty use a different list of Configurations.

Setting the list directly on the WebAppContext

If you have only one webapp that you wish to affect, this may be the easiest option. You will, however, either need to have a context xml file that represents your web app, or you need to call the equivalent in code. Let’s see an example of how we would add in the Configurations for both JNDI and annotations:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">

  <Set name="war"><SystemProperty name="jetty.base" default="."/>/webapps/my-cool-webapp</Set>

  <Set name="configurationClasses">
    <Array type="java.lang.String">
      <Item>org.eclipse.jetty.ee9.webapp.WebInfConfiguration</Item>
      <Item>org.eclipse.jetty.ee9.webapp.WebXmlConfiguration</Item>
      <Item>org.eclipse.jetty.ee9.webapp.MetaInfConfiguration</Item>
      <Item>org.eclipse.jetty.ee9.webapp.FragmentConfiguration</Item>
      <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
      <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
      <Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
      <Item>org.eclipse.jetty.ee9.webapp.JettyWebXmlConfiguration</Item>
    </Array>
  </Set>

</Configure>

Of course, you can also use this method to reduce the Configurations applied to a specific WebAppContext.

Setting the list for all webapps via the Deployer

If you use the deployer, you can set up the list of Configuration classes on the WebAppProvider. They will then be applied to each WebAppContext deployed by the deployer:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure id="Server" class="org.eclipse.jetty.server.Server">

  <Call name="addBean">
    <Arg>
      <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
        <Set name="contexts">
          <Ref refid="Contexts" />
        </Set>
        <Call id="webappprovider" name="addAppProvider">
          <Arg>
            <New class="org.eclipse.jetty.ee10.deployer.WebAppProvider">
              <Set name="monitoredDirName"><Property name="jetty.base" default="." />/webapps</Set>
              <Set name="configurationClasses">
                <Array type="java.lang.String">
                  <Item>org.eclipse.jetty.ee9.webapp.WebInfConfiguration</Item>
                  <Item>org.eclipse.jetty.ee9.webapp.WebXmlConfiguration</Item>
                  <Item>org.eclipse.jetty.ee9.webapp.MetaInfConfiguration</Item>
                  <Item>org.eclipse.jetty.ee9.webapp.FragmentConfiguration</Item>
                  <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
                  <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
                  <Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
                  <Item>org.eclipse.jetty.ee9.webapp.JettyWebXmlConfiguration</Item>
                </Array>
              </Set>
            </New>
          </Arg>
        </Call>
      </New>
    </Arg>
  </Call>
</Configure>
Adding or inserting to an existing list

Instead of having to enumerate the list in its entirety, you can simply nominate classes that you want to add, and indicate whereabouts in the list you want them inserted. Let’s look at an example of using this method to add in Configuration support for JNDI - as usual you can either do this in an xml file, or via equivalent code. This example uses an xml file, in fact it is the $JETTY_HOME/etc/jetty-plus.xml file from the Jetty distribution:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure id="Server" class="org.eclipse.jetty.server.Server">

  <!-- =========================================================== -->
  <!-- Add plus Configuring classes to all webapps for this Server -->
  <!-- =========================================================== -->
  <Call class="org.eclipse.jetty.ee9.webapp.Configuration$ClassList" name="setServerDefault">
    <Arg><Ref refid="Server" /></Arg>
    <Call name="addAfter">
      <Arg name="afterClass">org.eclipse.jetty.ee9.webapp.FragmentConfiguration</Arg>
      <Arg>
        <Array type="String">
          <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
          <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
        </Array>
      </Arg>
    </Call>
  </Call>

</Configure>

The org.eclipse.jetty.ee9.webapp.Configuration.ClassList class provides these methods for insertion:

addAfter

Inserts the supplied list of Configuration class names after the given Configuration class name.

addBefore

Inserts the supplied list of Configuration class names before the given Configuration class name.

Other Configuration

org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern

This is a context attribute that can be set on an org.eclipse.jetty.ee9.webapp.WebAppContext to control which parts of the container’s classpath should be processed for things like annotations, META-INF/resources, META-INF/web-fragment.xml and tlds inside META-INF.

Normally, nothing from the container classpath will be included for processing. However, sometimes you will need to include some. For example, you may have some libraries that are shared amongst your webapps and thus you have put them into a $JETTY_HOME/lib directory. The libraries contain annotations and therefore must be scanned.

The value of this attribute is a regexp that defines which jars and class directories from the container’s classpath should be examined.

Here’s an example from a context xml file (although as always, you could have accomplished the same in code), which would match any jar whose name starts with "foo-" or "bar-", or a directory named "classes":

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">

    <Call name="setAttribute">
      <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
      <Arg>.*/foo-[^/]*\.jar$|.*/bar-[^/]*\.jar$|.*/classes/.*</Arg>
    </Call>

</Configure>

Note that the order of the patterns defines the ordering of the scanning of the jars or class directories.

org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern

Similarly to the previous context attribute, this attribute controls which jars are processed for things like annotations, META-INF/resources, META-INF/web-fragment.xml and tlds in META-INF. However, this attribute controls which jars from the webapp’s classpath (usually WEB-INF/lib) are processed. This can be particularly useful when you have dozens of jars in WEB-INF/lib, but you know that only a few need to be scanned.

Here’s an example in a xml file of a pattern that matches any jar that starts with spring-:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">

    <Call name="setAttribute">
      <Arg>org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</Arg>
      <Arg>.*/spring-[^/]*\.jar$</Arg>
    </Call>

</Configure>

Note that the order of the patterns defines the ordering of the scanning of jar files.

Configuring Static Content Deployment

To serve purely static content, the Jetty Deployment Descriptor XML concepts and the internal ResourceHandler can be used. Create a file called scratch.xml in the ${jetty.base}/webapps directory and paste the following file contents in it.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
  <Set name="contextPath">/scratch</Set>
  <Set name="handler">
    <New class="org.eclipse.jetty.server.handler.ResourceHandler">
      <Set name="resourceBase">/home/scratch</Set>
      <Set name="directoriesListed">true</Set>
    </New>
  </Set>
</Configure>

This is a very basic setup for serving static files. For advanced static file serving, use the DefaultServlet.

Deployment Architecture

Jetty is built around an extensible Deployment Manager architecture complete with formal LifeCycle for Web Applications going through it.

For Jetty to serve content (static or dynamic), a ContextHandler needs to be configured and added to Jetty in the appropriate location. A pluggable DeploymentManager exists to make this process easier. The Jetty distribution contains example DeploymentManager configurations to deploy WAR files found in a directory to Jetty, and to deploy Jetty context xml files into Jetty as well.

The DeploymentManager is the heart of the typical webapp deployment mechanism; it operates as a combination of an Application LifeCycle Graph, Application Providers that find and provide Applications into the Application LifeCycle Graph, and a set of bindings in the graph that control the deployment process.

image

Application Providers

Before Jetty deploys an application, an AppProvider identifies the App and then provides it to the DeploymentManager. The main AppProvider with the Jetty distribution is the WebAppProvider.

Application LifeCycle Graph

The core feature of the DeploymentManager is the Application LifeCycle Graph.

image

The nodes and edges of this graph are pre-defined in Jetty along the most common actions and states found. These nodes and edges are not hardcoded; they can be adjusted and added to depending on need (for example, any complex requirements for added workflow, approvals, staging, distribution, coordinated deploys for a cluster or cloud, etc.).

New applications enter this graph at the Undeployed node, and the java.lang.String DeploymentManager.requestAppGoal(App,String) method pushes them through the graph.

LifeCycle Bindings

A set of default AppLifeCycle.Bindings defines standard behavior, and handles deploying, starting, stopping, and undeploying applications. If desired, custom AppLifeCycle.Bindings can be written and assigned anywhere on the Application LifeCycle graph.

Examples of new AppLifeCycle.Binding implementations that can be developed include:

  • Validating the incoming application.

  • Preventing the deployment of known forbidden applications.

  • Submitting the installation to an application auditing service in a corporate environment.

  • Distributing the application to other nodes in the cluster or cloud.

  • Emailing owner/admin of change of state of the application.

There are four default bindings:

  • StandardDeployer — Deploys the ContextHandler into Jetty in the appropriate place.

  • StandardStarter — Sets the ContextHandler to started and start accepting incoming requests.

  • StandardStopper — Stops the ContextHandler and stops accepting incoming requests.

  • StandardUndeployer — Removes the ContextHandler from Jetty.

image

A fifth, non-standard binding, called DebugBinding, is also available for debugging reasons; it logs the various transitions through the Application LifeCycle.

Using GlobalWebappConfigBinding

In addition to the LifeCycle bindings discussed above, there is also the GlobalWebappConfigBinding which, when added to the DeploymentManager will apply an additional configuration XML file to each webapp that it deploys. This can useful when setting server or system classes, or when defining override descriptors. This configuration XML file will be in addition to any context XML file that exists for the webapp; it will be applied after any context XML files but before the webapp is started. The format for the XML file is the same as any context XML file and can be used to same parameters for a webapp.

To use this binding, you can either modify the existing jetty-deploy.xml which comes with the Jetty distribution (be sure to copy it to your $JETTY_BASE/etc directory first), or by creating a new module file which calls to an additional XML file.

        <Call name="addLifeCycleBinding">
          <Arg>
            <New class="org.eclipse.jetty.ee10.deployer.GlobalWebappConfigBinding" >
              <Set name="jettyXml"><Property name="jetty.home" default="." />/etc/global-webapp-config.xml</Set>
            </New>
          </Arg>
        </Call>

Understanding the Default WebAppProvider

The WebAppProvider is used for the deployment of Web Applications packaged as WAR files, expanded as a directory, or declared in a Jetty Deployable Descriptor XML File. It supports hot (re)deployment.

The basic operation of the WebAppProvider is to periodically scan a directory for deployables. In the standard Jetty Distribution, this is configured in the ${jetty.home}/etc/jetty-deploy.xml file.

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">

  <Call name="addBean">
    <Arg>
      <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
        <Set name="contexts">
          <Ref refid="Contexts" />
        </Set>
        <Call id="webappprovider" name="addAppProvider">
          <Arg>
            <New class="org.eclipse.jetty.ee10.deployer.WebAppProvider">
              <Set name="monitoredDirName"><Property name="jetty.home" default="." />/webapps</Set>
              <Set name="defaultsDescriptor"><Property name="jetty.home" default="." />/etc/webdefault.xml</Set>
              <Set name="scanInterval">1</Set>
              <Set name="extractWars">true</Set>
            </New>
          </Arg>
        </Call>
      </New>
    </Arg>
  </Call>
</Configure>

The above configuration will create a DeploymentManager tracked as a Server LifeCycle Bean, with the following configuration.

contexts

A passed in reference to the HandlerContainer into which the discovered webapps are deployed. This is normally a reference that points to the id="Contexts" found in the ${jetty.home}/etc/jetty.xml file, which itself is an instance of ContextHandlerCollection.

monitoredDirName

The file path or URL to the directory to scan for web applications.

Scanning follows these rules:
  1. A base directory must exist.

  2. Hidden Files (starting with ".") are ignored.

  3. Directories with names ending in ".d" are ignored.

  4. Common CVS directories "CVS" and "CVSROOT" are ignored.

  5. Any *.war files are considered automatic deployables.

  6. Any *.xml files are considered context descriptor deployables.

  7. In the special case where both a WAR file and XML file exists for same base name, the XML file is assumed to configure and reference the WAR file (see Configuring a Specific Web Application Deployment). Since jetty-9.2.7, if either the WAR file or its corresponding XML file changes, the webapp will be redeployed.

  8. A directory is considered to be deployable.

  9. In the special case where both a Directory and WAR file of the same name exists, the WAR file is assumed to be an automatic deployable.

  10. In the special case where both a Directory and XML file of the same name exists, the XML file is assumed to configure and reference the Directory.

  11. All other directories are subject to automatic deployment.

  12. If automatic deployment is used, and the special filename root.war/ROOT.war or directory name root/ROOT will result in a deployment to the "/" context path.

defaultsDescriptor

Specifies the default Servlet web descriptor to use for all Web Applications. The intent of this descriptor is to include common configuration for the Web Application before the Web Application’s own /WEB-INF/web.xml is applied. The ${jetty.home}/etc/webdefault.xml that comes with the Jetty distribution controls the configuration of the JSP and Default servlets, along with MIME-types and other basic metadata.

scanInterval

The period in seconds between sweeps of the monitoredDirName for changes: new contexts to deploy, changed contexts to redeploy, or removed contexts to undeploy.

extractWars

If parameter is true, any packed WAR or zip files are first extracted to a temporary directory before being deployed. This is advisable if there are uncompiled JSPs in the web apps.

parentLoaderPriority

Parameter is a boolean that selects whether the standard Java parent first delegation is used or the servlet specification webapp classloading priority. The latter is the default.

Quickstart Webapps

The auto discovery features of the Servlet specification can make deployments slow and uncertain. Auto discovery of Web Application configuration can be useful during the development of a webapp as it allows new features and frameworks to be enabled simply by dropping in a jar file. However, for deployment, the need to scan the contents of many jars can have a significant impact of the start time of a webapp.

With the release of Jetty 9.2, a quickstart module was included which allows a webapp to be pre-scanned and preconfigured. This means that all the scanning is done prior to deployment and all configuration is encoded into an effective web.xml, called WEB-INF/quickstart-web.xml, which can be inspected to understand what will be deployed before deploying. Not only does the quickstart-web.xml contain all the discovered Servlets, Filters and Constraints, but it also encodes as context parameters all discovered:

  • ServletContainerInitializers

  • HandlesTypes classes

  • Taglib Descriptors

With the quickstart mechanism, Jetty is able to entirely bypass all scanning and discovery modes and start a webapp in a predictable and fast way. Tests have shown that webapps that took many seconds to scan and deploy can now be deployed in a few hundred milliseconds.

Setting up Quickstart

Prerequisites
Jetty Distribution

In a standard Jetty distribution the quickstart module can be configured with the following command:

$ java -jar $JETTY_HOME/start.jar --add-to-start=quickstart
Embedded

In a Maven project you add a dependency on the artifact jetty-quickstart.

<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-quickstart</artifactId>
    <version>12.0.9-SNAPSHOT</version>
</dependency>
Configuration

Webapps need to be instances of org.eclipse.jetty.quickstart.QuickStartWebApp rather than the normal org.eclipse.jetty.ee9.webapp.WebAppContext.

org.eclipse.jetty.quickstart.QuickStartWebApp instances offer the same setters as the familiar org.eclipse.jetty.ee9.webapp.WebAppContext, with the addition of:

autoPreconfigure

(true/false). If true, the first time the webapp is run, the WEB-INF/quickstart-web.xml is generated BEFORE the webapp is deployed. Subsequent runs use the previously generated quickstart file.

originAttribute

The name of an attribute to insert into the generated elements in quickstart-web.xml that gives the origin of the element. By default it is origin.

generateOrigin

(true/false). By default it is false. If true, the origin attribute will be inserted into each element in quickstart-web.xml. Note that origin attributes will also be generated if debug log level is enabled.

If you are using Spring-Boot you must set generateOrigin to true.

The origin is either a descriptor eg web.xml,web-fragment.xml,override-web.xml file, or an annotation eg @WebServlet. For xml validation each attribute must be unique, and therefore an integer counter is appended to each value. Some examples of elements with origin attribute information are:

<listener origin="DefaultsDescriptor(file:///path/to/distro/etc/webdefault.xml):21">
<listener origin="WebDescriptor(file:///path/to/base/webapps/test-spec/WEB-INF/web.xml):22">
<servlet-class origin="FragmentDescriptor(jar:file:///path/to/base/webapps/test-spec/WEB-INF/lib/test-web-fragment.jar!/META-INF/web-fragment.xml):23">
<servlet-class origin="@WebServlet(com.acme.test.TestServlet):24">
In XML

If a web application already has a context xml file, eg webapps/myapp.xml file, simply change the class in the Configure element. Otherwise, create a context xml file with the following information (in addition to the usual setting of contextPath, war etc):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.quickstart.QuickStartWebApp">
  <Set name="autoPreconfigure">true</Set>
</Configure>
In Code

Create an instance of org.eclipse.jetty.quickstart.QuickStartWebApp rather than the normal org.eclipse.jetty.ee9.webapp.WebAppContext. You then use the QuickStartWebApp instance in exactly the same way that you would a WebAppContext.

Here’s a snippet:

    QuickStartWebApp webapp = new QuickStartWebApp();
    webapp.setAutoPreconfigure(true);
Pre-generating the quickstart-web.xml file

Rather than use the autoPreconfigure feature of the QuickStartWebApp - which lazily generates the quickstart-web.xml file - you can eagerly pre-generate it for an existing war by invoking as a main class org.eclipse.jetty.quickstart.PreconfigureQuickStartWar. Note that you will need to provide all necessary jetty jars on the command line classpath. This will unpack the war if necessary, and create the quickstart-web.xml before the first deployment:

$ java -cp [jetty classpath] org.eclipse.jetty.quickstart.PreconfigureQuickStartWar myapp.war

Run the class with no arguments to see other runtime options.

Alternatively, you could use the Jetty Maven Plugin goal jetty:effective-web-xml: this will generate quickstart information, but print it to stderr. The goal provides a configuration option to save the output to a file, which you can then copy into your webapp’s WEB-INF dir. Note that as the Jetty Maven Plugin is a general tool for running webapps, it may have more jars on its classpath than are needed by your application, and thus may generate extra quickstart information: we recommend that you use this goal only as a quick guide to the type of information that quickstart generates.

Avoiding TLD Scans with precompiled JSPs

Of course precompiling JSPs is an excellent way to improve the start time of a web application. As of Jetty 9.2 the Apache Jasper JSP implementation has been used and has been augmented to allow the TLD scan to be skipped. This can be done by adding a context-param to the web.xml file (this is done automatically by the Jetty Maven JSPC plugin):

<context-param>
  <param-name>org.eclipse.jetty.jsp.precompiled</param-name>
  <param-value>true</param-value>
</context-param>

Bypassing start.jar

The Jetty start.jar mechanism is a very powerful and flexible mechanism for constructing a classpath and executing a configuration encoded in Jetty XML format. However, this mechanism does take some time to build the classpath. The start.jar mechanism can be bypassed by using the –dry-run option to generate and reuse a complete command line to start Jetty at a later time:

$ RUN=$(java -jar $JETTY_HOME/start.jar --dry-run)
$ eval $RUN

Note that --dry-run may create a properties file in the temp directory and include it on the generated command line. If so, then a copy of the temporary properties file should be taken and the command line updated with it’s new persistent location.

Embedding

Jetty Embedded HelloWorld

This section provides a tutorial that shows how you can quickly develop embedded code against the Jetty API.

Downloading the Jars

Jetty is decomposed into many jars and dependencies to achieve a minimal footprint by selecting the minimal set of jars. Typically it is best to use something like Maven to manage jars, however this tutorial uses an aggregate Jar that contains all of the required Jetty classes in one Jar. You can manually download the aggregate jetty-all.jar using curl or a browser.

The central Maven repository has started to aggressively reject/deny access to the repository from the wget command line tool (due to abusive use of the tool by some groups). The administrators of the central maven repository have stated that the recommended command line download tool is now curl.
The jetty-all jar referenced in this section is for example purposes only and should not be used outside of this context. Please consider using Maven to manage your project dependencies.

Use curl as follows:

> mkdir Demo
> cd Demo
> curl -o jetty-all-uber.jar https://repo1.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/12.0.9-SNAPSHOT/jetty-all-12.0.9-SNAPSHOT-uber.jar

Writing a HelloWorld Example

The Embedding Jetty section contains many examples of writing against the Jetty API. This tutorial uses a simple HelloWorld handler with a main method to run the server. You can either download or create in an editor the file HelloWorld.java with the following content:

Unresolved directive in embedding/jetty-helloworld.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloWorld.java[]

Compiling the HelloWord example

The following command compiles the HelloWorld class:

> mkdir classes
> javac -d classes -cp jetty-all-uber.jar HelloWorld.java

Running the Handler and Server

The following command runs the HelloWorld example:

> java -cp classes:jetty-all-uber.jar org.eclipse.jetty.demos.HelloWorld

You can now point your browser at http://localhost:8080 to see your hello world page.

Next Steps

To learn more about Jetty, take these next steps:

Embedding Jetty

Jetty has a slogan, "Don’t deploy your application in Jetty, deploy Jetty in your application!" What this means is that as an alternative to bundling your application as a standard WAR to be deployed in Jetty, Jetty is designed to be a software component that can be instantiated and used in a Java program just like any POJO. Put another way, running Jetty in embedded mode means putting an HTTP module into your application, rather than putting your application into an HTTP server.

This tutorial takes you step-by-step from the simplest Jetty server instantiation to running multiple web applications with standards-based deployment descriptors. The source for most of these examples is part of the standard Jetty project.

Overview

To embed a Jetty server the following steps are typical and are illustrated by the examples in this tutorial:

  1. Create a Server instance.

  2. Add/Configure Connectors.

  3. Add/Configure Handlers and/or Contexts and/or Servlets.

  4. Start the Server.

  5. Wait on the server or do something else with your thread.

Creating the Server

The following code from SimplestServer.java instantiates and runs the simplest possible Jetty server:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java[]

This runs an HTTP server on port 8080. It is not a very useful server as it has no handlers, and thus returns a 404 error for every request.

Using Handlers

To produce a response to a request, Jetty requires that you set a Handler on the server. A handler may:

  • Examine/modify the HTTP request.

  • Generate the complete HTTP response.

  • Call another Handler (see HandlerWrapper).

  • Select one or many Handlers to call (see HandlerCollection).

HelloWorld Handler

The following code based on HelloHandler.java shows a simple hello world handler:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloHandler.java[]

The parameters passed to the handle method are:

  • target – the target of the request, which is either a URI or a name from a named dispatcher.

  • baseRequest – the Jetty mutable request object, which is always unwrapped.

  • request – the immutable request object, which may have been wrapped by a filter or servlet.

  • response – the response, which may have been wrapped by a filter or servlet.

The handler sets the response status, content-type, and marks the request as handled before it generates the body of the response using a writer.

Running HelloWorldHandler

To allow a Handler to handle HTTP requests, you must add it to a Server instance. The following code from OneHandler.java shows how a Jetty server can use the HelloWorld handler:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneHandler.java[]

One or more handlers do all request handling in Jetty. Some handlers select other specific handlers (for example, a ContextHandlerCollection uses the context path to select a ContextHandler); others use application logic to generate a response (for example, the ServletHandler passes the request to an application Servlet), while others do tasks unrelated to generating the response (for example, RequestLogHandler or StatisticsHandler).

Later sections describe how you can combine handlers like aspects. You can see some of the handlers available in Jetty in the org.eclipse.jetty.server.handler package.

Handler Collections and Wrappers

Complex request handling is typically built from multiple Handlers that you can combine in various ways. Jetty has several implementations of the HandlerContainer interface:

HandlerCollection

Holds a collection of other handlers and calls each handler in order. This is useful for combining statistics and logging handlers with the handler that generates the response.

HandlerList

A Handler Collection that calls each handler in turn until either an exception is thrown, the response is committed or the request.isHandled() returns true. You can use it to combine handlers that conditionally handle a request, such as calling multiple contexts until one matches a virtual host.

HandlerWrapper

A Handler base class that you can use to daisy chain handlers together in the style of aspect-oriented programming. For example, a standard web application is implemented by a chain of a context, session, security and servlet handlers.

ContextHandlerCollection

A specialized HandlerCollection that uses the longest prefix of the request URI (the contextPath) to select a contained ContextHandler to handle the request.

Scoped Handlers

Much of the standard Servlet container in Jetty is implemented with HandlerWrappers that daisy chain handlers together: ContextHandler to SessionHandler to SecurityHandler to ServletHandler. However, because of the nature of the servlet specification, this chaining cannot be a pure nesting of handlers as the outer handlers sometimes need information that the inner handlers process. For example, when a ContextHandler calls some application listeners to inform them of a request entering the context, it must already know which servlet the ServletHandler will dispatch the request to so that the servletPath method returns the correct value.

The HandlerWrapper is specialized to the ScopedHandler abstract class, which supports a daisy chain of scopes. For example if a ServletHandler is nested within a ContextHandler, the order and nesting of execution of methods is:

Server.handle(...)
  ContextHandler.doScope(...)
    ServletHandler.doScope(...)
      ContextHandler.doHandle(...)
        ServletHandler.doHandle(...)
          SomeServlet.service(...)

Thus when the ContextHandler handles the request, it does so within the scope the ServletHandler has established.

Resource Handler

The FileServer example shows how you can use a ResourceHandler to serve static content from the current working directory:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java[]

Notice that a HandlerList is used with the ResourceHandler and a DefaultHandler, so that the DefaultHandler generates a good 404 response for any requests that do not match a static resource.

Embedding Connectors

In the previous examples, the Server instance is passed a port number and it internally creates a default instance of a Connector that listens for requests on that port. However, often when embedding Jetty it is desirable to explicitly instantiate and configure one or more Connectors for a Server instance.

One Connector

The following example, OneConnector.java, instantiates, configures, and adds a single HTTP connector instance to the server:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneConnector.java[]

In this example the connector handles the HTTP protocol, as that is the default for the ServerConnector class.

Many Connectors

When configuring multiple connectors (for example, HTTP and HTTPS), it may be desirable to share configuration of common parameters for HTTP. To achieve this you need to explicitly configure the ServerConnector class with ConnectionFactory instances, and provide them with common HTTP configuration.

The ManyConnectors example, configures a server with two ServerConnector instances: the http connector has a HTTPConnectionFactory instance; the https connector has a SslConnectionFactory chained to a HttpConnectionFactory. Both HttpConnectionFactory are configured based on the same HttpConfiguration instance, however the HTTPS factory uses a wrapped configuration so that a SecureRequestCustomizer can be added.

Embedding Servlets

Servlets are the standard way to provide application logic that handles HTTP requests. Servlets are similar to a Jetty Handler except that the request object is not mutable and thus cannot be modified. Servlets are handled in Jetty by a ServletHandler. It uses standard path mappings to match a Servlet to a request; sets the requests servletPath and pathInfo; passes the request to the servlet, possibly via Filters to produce a response.

The MinimalServlets example creates a ServletHandler instance and configures a single HelloServlet:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java[]

Embedding Contexts

A ContextHandler is a ScopedHandler that responds only to requests that have a URI prefix that matches the configured context path. Requests that match the context path have their path methods updated accordingly and the contexts scope is available, which optionally may include:

  • A Classloader that is set as the Thread context classloader while request handling is in scope.

  • A set of attributes that is available via the ServletContext API.

  • A set of init parameters that is available via the ServletContext API.

  • A base Resource which is used as the document root for static resource requests via the ServletContext API.

  • A set of virtual host names.

The following OneContext example shows a context being established that wraps the HelloHandler:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneContext.java[]

When many contexts are present, you can embed a ContextHandlerCollection to efficiently examine a request URI to then select the matching ContextHandler(s) for the request. The ManyContexts example shows how many such contexts you can configure:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java[]

Embedding ServletContexts

A ServletContextHandler is a specialization of ContextHandler with support for standard sessions and Servlets. The following OneServletContext example instantiates a DefaultServlet to server static content from /tmp/ and a DumpServlet that creates a session and dumps basic details about the request:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContext.java[]

Embedding Web Applications

A WebAppContext is an extension of a ServletContextHandler that uses the standard layout and web.xml to configure the servlets, filters and other features from a web.xml and/or annotations. The following OneWebApp example configures the Jetty test webapp. Web applications can use resources the container provides, and in this case a LoginService is needed and also configured:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java[]

Like Jetty XML

The typical way to configure an instance of the Jetty server is via jetty.xml and associated configuration files. However the Jetty XML configuration format is just a simple rendering of what you can do in code; it is very simple to write embedded code that does precisely what the jetty.xml configuration does. The LikeJettyXml example following renders in code the behavior obtained from the configuration files:

Unresolved directive in embedding/embedding-jetty.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java[]

Embedded Examples

Jetty has a rich history of being embedded into a wide variety of applications. In this section we will walk you through a number of our simple examples under our embedded-jetty-examples project in our git repository.

These files are pulled directly from our git repository when this document is generated. If the line numbers do not line up feel free to fix this documentation in github and give us a pull request, or at least open an issue to notify us of the discrepancy.

Simple File Server

This example shows how to create a simple file server in Jetty. It is perfectly suitable for test cases where you need an actual web server to obtain a file from, it could easily be configured to serve files from a directory under src/test/resources. Note that this does not have any logic for caching of files, either within the server or setting the appropriate headers on the response. It is simply a few lines that illustrate how easy it is to serve out some files.

Unresolved directive in embedding/examples/embedded-file-server.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java[]
Run it!

After you have started things up you should be able to navigate to http://localhost:8080/index.html (assuming one is in the resource base directory) and you are good to go.

Maven Coordinates

To use this example in your project you will need the following Maven dependencies declared.

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-server</artifactId>
  <version>${project.version}</version>
</dependency>

Split File Server

This example builds on the Simple File Server to show how chaining multiple ResourceHandlers together can let you aggregate multiple directories to serve content on a single path and how you can link these together with ContextHandlers.

Unresolved directive in embedding/examples/embedded-split-file-server.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/SplitFileServer.java[]
Run it!

After you have started things up you should be able to navigate to http://localhost:8090/index.html (assuming one is in the resource base directory) and you are good to go. Any requests for files will be looked for in the first resource handler, then the second, and so on and so forth.

Maven Coordinates

To use this example as is in your project you will need the following maven dependencies declared. We would recommend not using the toolchain dependency in your actual application.

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-server</artifactId>
  <version>${project.version}</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty.toolchain</groupId>
  <artifactId>jetty-test-helper</artifactId>
  <version>2.2</version>
</dependency>

Multiple Connectors

This example shows how to configure Jetty to use multiple connectors, specifically so it can process both http and https requests. Since the meat of this example is the server and connector configuration it only uses a simple HelloHandler but this example should be easily merged with other examples like those deploying servlets or webapps.

Unresolved directive in embedding/examples/embedded-many-connectors.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java[]
Walkthrough

Start things up! By using the server.join() the server thread will join with the current thread. See Thread.join() for more details.

Maven Coordinates

To use this example in your project you will need the following Maven dependencies declared.

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-server</artifactId>
  <version>${project.version}</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-security</artifactId>
  <version>${project.version}</version>
</dependency>

Secured Hello Handler

This example shows how to wrap one handler with another one that handles security. We have a simple Hello Handler that just return a greeting but add on the restriction that to get this greeting you must authenticate. Another thing to remember is that this example uses the ConstraintSecurityHandler which is what supports the security mappings inside of the servlet api, it could be easier to show just the SecurityHandler usage, but the constraint provides more configuration power. If you don’t need that you can drop the Constraint bits and use just the SecurityHandler.

Unresolved directive in embedding/examples/embedded-secured-hello-handler.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java[]
Run it!

After you have started things up you should be able to navigate to http://localhost:8080/index.html (assuming one is in the resource base directory) and you are good to go.

The Realm Properties File
Unresolved directive in embedding/examples/embedded-secured-hello-handler.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/test/resources/realm.properties[]
Maven Coordinates

To use this example in your project you will need the following Maven dependencies declared.

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-server</artifactId>
  <version>${project.version}</version>
</dependency>

Minimal Servlet

This example shows the bare minimum required for deploying a servlet into Jetty. Note that this is strictly a servlet, not a servlet in the context of a web application, that example comes later. This is purely just a servlet deployed and mounted on a context and able to process requests. This example is excellent for situations where you have a simple servlet that you need to unit test, just mount it on a context and issue requests using your favorite http client library (like our Jetty client found in [client-http]).

Unresolved directive in embedding/examples/embedded-minimal-servlet.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java[]
Walkthrough

Start things up! By using the server.join() the server thread will join with the current thread. See Thread.join() for more details.

It is really simple to create useful servlets for testing behaviors. Sometimes you need a http server to run a unit test against that will return test content and wiring up a servlet like this makes it trivial.

After you have started things up you should be able to navigate to http://localhost:8080/ and you are good to go.

Maven Coordinates

To use this example in your project you will need the following Maven dependencies declared.

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-servlet</artifactId>
  <version>${project.version}</version>
</dependency>

Web Application

This example shows how to deploy a simple webapp with an embedded instance of Jetty. This is useful when you want to manage the lifecycle of a server programmatically, either within a production application or as a simple way to deploying and debugging a full scale application deployment. In many ways it is easier then traditional deployment since you control the classpath yourself, making this easy to wire up in a test case in Maven and issue requests using your favorite http client library (like our Jetty client found in [client-http]).

Unresolved directive in embedding/examples/embedded-one-webapp.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java[]
Run it!

After you have started things up you should be able to navigate to http://localhost:8080/ and you are good to go.

Maven Coordinates

To use this example in your project you will need the following Maven dependencies declared.

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-webapp</artifactId>
  <version>${project.version}</version>
</dependency>

Web Application with JSP

This example is very similar to the one in the previous section, although it enables the embedded webapp to use JSPs. As of jetty-9.2, we use the JSP engine from Apache, which relies on a Servlet Specification 3.1 style ServletContainerInitializer to initialize itself. To get this to work with Jetty, you need to enable annotations processing, as shown in this example code:

Unresolved directive in embedding/embedded-examples.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebAppWithJsp.java[]
Run it!

After you have started things up you should be able to navigate to http://localhost:8080/jsp/ and click on any of the links to jsps.

Maven Coordinates

To use this example in your project, you will need the following Maven dependencies declared, in addition to those from the previous section:

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-annotations</artifactId>
  <version>${project.version}</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>apache-jsp</artifactId>
  <version>${project.version}</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>apache-jstl</artifactId>
  <version>${project.version}</version>
</dependency>

Adding Examples

If you would like to add an example to this list, fork the documentation project from github (see the blue bar at the bottom of this page) and add the new page. Feel free to add the example contents directly as a [source.java] and we will take it from there.

If you feel and example is missing, feel free to open a bug to ask for it. No guarantees, but the more helpful and demonstrative it is the better.

Provided Servlets, Filters, and Handlers

Jetty ships with a bundle of servlets that interact with the key classes. Most are in the org.eclipse.jetty.servlets package. These servlets and filters are among the principle elements of Jetty as a component-based infrastructure that holds and runs J2EE applications. As described, they play a major role in running and maintaining the Jetty server.

Also included are a number of Jetty specific handlers that allow access to internals of jetty that would not normally be exposed and are very useful testing environments and many production scenarios.

Default Servlet

Info

Usage

The DefaultServlet implements the ResourceFactory interface and extends the HttpServlet abstract class. It is usually mapped to "/" and provides handling for static content, OPTION and TRACE methods for the context. The MOVE method is allowed if PUT and DELETE are allowed. See the DefaultServlet javadoc.

Init Parameters

Jetty supports the following initParameters:

acceptRanges

If true, range requests and responses are supported.

dirAllowed

If true, directory listings are returned if no welcome file is found. Otherwise 403 Forbidden displays.

redirectWelcome

If true, welcome files are redirected rather that forwarded.

welcomeServlets

If true, attempt to dispatch to welcome files that are servlets, but only after no matching static resources could be found. If false, then a welcome file must exist on disk. If exact, then exact servlet matches are supported without an existing file. Default is false. This must be false if you want directory listings, but have index.jsp in your welcome file list.

precompressed

If set to a comma separated list of encoding types (that may be listed in a requests Accept-Encoding header) to file extension mappings to look for and serve. For example: br=.br,gzip=.gz,bzip2=.bz. If set to a boolean true, then a default set of compressed formats will be used, otherwise no precompressed formats supported.

gzip

Deprecated. Use precompressed instead. If set to true, then static content is served as gzip content encoded if a matching resource is found ending with ".gz".

resourceBase

Set to replace the context resource base.

resourceCache

If set, this is a context attribute name, which the servlet will use to look for a shared ResourceCache instance.

relativeResourceBase

Set with a pathname relative to the base of the servlet context root. Useful for only serving static content out of only specific subdirectories.

cacheControl

If set, all static content will have this value set as the cache-control header.

pathInfoOnly

If true, only the path info will be applied to the resourceBase

stylesheet

Set with the location of an optional stylesheet that will be used to decorate the directory listing html.

etags

If true, weak etags will be generated and handled.

maxCacheSize

Maximum total size of the cache or 0 for no cache.

maxCachedFileSize

Maximum size of a file to cache.

maxCachedFiles

Maximum number of files to cache.

useFileMappedBuffer

If set to true, mapped file buffer serves static content. Setting this value to false means that a direct buffer is used instead of a mapped file buffer. By default, this is set to true.

otherGzipFileExtensions

A comma separated list of other file extensions that signify that a file is gzip compressed. If you don’t explicitly set this, it defaults to .svgz.

encodingHeaderCacheSize

Max entries in a cache of ACCEPT-ENCODING headers

Proxy Servlet

Info

Usage

An asynchronous servlet that forwards requests to another server either as a standard web reverse proxy (as defined by RFC2616) or as a transparent reverse proxy. Internally it uses the async jetty-client.

To facilitate JMX monitoring, the HttpClient instance is set as context attribute, prefixed with the servlet’s name and exposed by the mechanism provided by ContextHandler.MANAGED_ATTRIBUTES.

Init Parameters

The following init parameters may be used to configure the servlet:

hostHeader

forces the host header to a particular value

viaHost

the name to use in the Via header: Via: http/1.1 <viaHost>

whiteList

comma-separated list of allowed proxy hosts

blackList

comma-separated list of forbidden proxy hosts

In addition, there are a number of init parameters that can be used to configure the HttpClient instance used internally for the proxy.

maxThreads

Default Value: 256 The max number of threads of HttpClient’s Executor

maxConnections

Default Value: 32768 The max number of connections per destination. RFC 2616 suggests that 2 connections should be opened per each destination, but browsers commonly open 6 or more. If this HttpClient is used for load testing, it is common to have only one destination (the server to load test), and it is recommended to set this value to a high value (at least as much as the threads present in the executor).

idleTimeout

Default Value: 30000 The idle timeout in milliseconds that a connection can be idle, that is without traffic of bytes in either direction.

timeout

Default Value: 60000 The total timeout in milliseconds for the request/response conversation.

requestBufferSize

Default Value: 4096 The size of the request buffer the request is written into.

responseBufferSize

Default Value: 4096 The size of the response buffer the response is written into.

Balancer Servlet

Info

Usage

The Balancer servlet allows for simple, sticky round robin load balancing leveraging the ProxyServlet that is distributed with Jetty.

In addition to the parameters for ProxyServlet, the following are available for the balancer servlet:

stickySessions

True if sessions should be sticky for subsequent requests

balancerMember.<name>.proxyTo

One of more of these are required and will be the locations that are used to proxy traffic to. Unresolved directive in extras/chapter.adoc - include::qos-filter.adoc[]

Denial of Service Filter

Info

Usage

The Denial of Service (DoS) filter limits exposure to request flooding, whether malicious, or as a result of a misconfigured client. The DoS filter keeps track of the number of requests from a connection per second. If the requests exceed the limit, Jetty rejects, delays, or throttles the request, and sends a warning message. The filter works on the assumption that the attacker might be written in simple blocking style, so by suspending requests you are hopefully consuming the attacker’s resources.

Using the DoS Filter

Jetty places throttled requests in a queue, and proceed only when there is capacity available.

Required JARs

To use the DoS Filter, these JAR files must be available in WEB-INF/lib:

  • $JETTY_HOME/lib/jetty-util.jar

  • $JETTY_HOME/lib/jetty-servlets.jar

Sample Configuration

Place the configuration in a webapp’s web.xml or jetty-web.xml. The default configuration allows 25 requests per connection at a time, servicing more important requests first, and queuing up the rest. This example allow 30 requests at a time:

<filter>
   <filter-name>DoSFilter</filter-name>
   <filter-class>org.eclipse.jetty.ee9.servlets.DoSFilter</filter-class>
   <init-param>
     <param-name>maxRequestsPerSec</param-name>
     <param-value>30</param-value>
   </init-param>
 </filter>
Configuring DoS Filter Parameters

The following init parameters control the behavior of the filter:

maxRequestsPerSec

Maximum number of requests from a connection per second. Requests in excess of this are first delayed, then throttled. Default is 25.

delayMs

Delay imposed on all requests over the rate limit, before they are considered at all:

  • 100 (ms) = Default

  • -1 = Reject request

  • 0 = No delay

  • any other value = Delay in ms

maxWaitMs

Length of time, in ms, to blocking wait for the throttle semaphore. Default is 50 ms.

throttledRequests

Number of requests over the rate limit able to be considered at once. Default is 5.

throttleMs

Length of time, in ms, to async wait for semaphore. Default is 30000L.

maxRequestMs

Length of time, in ms, to allow the request to run. Default is 30000L.

maxIdleTrackerMs

Length of time, in ms, to keep track of request rates for a connection, before deciding that the user has gone away, and discarding it. Default is 30000L.

insertHeaders

If true, insert the DoSFilter headers into the response. Defaults to true.

remotePort

If true, then rate is tracked by IP and port (effectively connection). Defaults to false.

ipWhitelist

A comma-separated list of IP addresses that will not be rate limited.

managedAttr

If set to true, then this servlet is set as a ServletContext attribute with the filter name as the attribute name. This allows a context external mechanism (for example, JMX via ContextHandler.MANAGED_ATTRIBUTES) to manage the configuration of the filter.

Header Filter

Info

Usage

The header filter sets or adds headers to each response based on an optionally included/excluded list of path specs, mime types, and/or HTTP methods. This filter processes its configured headers before calling doFilter in the filter chain. Some of the headers configured in this filter may get overwritten by other filters and/or the servlet processing the request.

Required JARs

To use the Header Filter, these JAR files must be available in WEB-INF/lib:

  • $JETTY_HOME/lib/jetty-http.jar

  • $JETTY_HOME/lib/jetty-servlets.jar

  • $JETTY_HOME/lib/jetty-util.jar

Sample Configuration

Place the configuration in a webapp’s web.xml or jetty-web.xml. This filter will perform the following actions on each response:

  • Set the X-Frame-Options header to DENY.

  • Add a Cache-Control header containing no-cache, no-store, must-revalidate

  • Set the Expires header to approximately one year in the future.

  • Add a Date header with the current system time.

Each action must be separated by a comma.
<filter>
   <filter-name>HeaderFilter</filter-name>
   <filter-class>org.eclipse.jetty.ee9.servlets.HeaderFilter</filter-class>
   <init-param>
     <param-name>headerConfig</param-name>
     <param-value>
      set X-Frame-Options: DENY,
      "add Cache-Control: no-cache, no-store, must-revalidate",
      setDate Expires: 31540000000,
      addDate Date: 0
     </param-value>
   </init-param>
 </filter>
Configuring Header Filter Parameters

The following init parameters control the behavior of the filter:

includedPaths

Optional. Comma separated values of included path specs.

excludedPaths

Optional. Comma separated values of excluded path specs.

includedMimeTypes

Optional. Comma separated values of included mime types. The mime type will be guessed from the extension at the end of the request URL if the content type has not been set on the response.

excludedMimeTypes

Optional. Comma separated values of excluded mime types. The mime type will be guessed from the extension at the end of the request URL if the content type has not been set on the response.

includedHttpMethods

Optional. Comma separated values of included http methods.

excludedHttpMethods

Optional. Comma separated values of excluded http methods.

headerConfig

Comma separated values of actions to perform on headers. The syntax for each action is action headerName: headerValue.

Supported header actions:

  • set - causes set setHeader to be called on the response

  • add - causes set addHeader to be called on the response

  • setDate - causes setDateHeader to be called on the response.

  • addDate - causes addDateHeader to be called on the response.

If setDate or addDate is used, headerValue should be the number of milliseconds to add to the current system time before writing the header value.

If a property is both included and excluded by the filter configuration, then it will be considered excluded.

Path spec rules:

  • If the spec starts with ^, the spec is assumed to be a regex based path spec and will match with normal Java regex rules.

  • If the spec starts with /, the spec is assumed to be a Servlet url-pattern rules path spec for either an exact match or prefix based match.

  • If the spec starts with *., the spec is assumed to be a Servlet url-pattern rules path spec for a suffix based match.

  • All other syntaxes are unsupported.

Gzip Handler

Info

Usage

The Jetty GzipHandler is a compression handler that you can apply to any dynamic resource (servlet). It fixes many of the bugs in commonly available compression filters: it works with asynchronous servlets; it handles all ways to set content length. Some user-agents might be excluded from compression to avoid common browser bugs (yes, this means IE!).

The GzipHandler can be added to the entire server by enabling the gzip.mod module. It may also be added to individual contexts in a context xml file.

Jetty 9 only compresses using GZip. Using deflate HTTP compression is not supported and will not function.

Gzip Rules

GzipHandler will gzip the content of a response if:

  • It is mapped to a matching path

  • The request method is configured to support gzip

  • The request is not from an excluded User-Agent

  • accept-encoding header is set to gzip

  • The response status code is >=200 and <300

  • The content length is unknown or more than the minGzipSize initParameter or the minGzipSize is 0(default)

  • The content-type does not match an excluded mime-type

  • No content-encoding is specified by the resource

Compressing the content can greatly improve the network bandwidth usage, but at the cost of memory and CPU cycles. The DefaultServlet is capable of serving pre-compressed static content, which saves memory and CPU.

The GzipHandler installs an output interceptor which passes through to the DefaultServlet. If the content served by DefaultServlet is already compressed, the GzipHandler does nothing; if it is not compressed, the content is compressed on-the-fly.

Automatic precompression by the DefaultServlet can be configured. Read more about the DefaultServlet here.

Gzip Configuration

minGzipSize

Content will only be compressed if content length is either unknown or greater than minGzipSize.

checkGzExists (Deprecated)

False by default. If set to true, the handler will check for pre-compressed content.

includedMethods

List of HTTP methods to compress. If not set, only GET requests are compressed.

includedMimeTypes

List of MIME types to compress.

excludedMimeTypes

List of MIME types not to compress.

excludedAgentPatterns

A list of regex patterns for User-Agent names from which requests should not be compressed.

excludedPaths

List of paths to exclude from compression. Performs a String.startsWith(String) comparison to check if the path matches. If it does match then there is no compression. To match subpaths use excludePathPatterns instead.

includedPaths

List of paths to consider for compression.

includePaths

List of paths to definitely consider for compression.

Cross Origin Filter

Info

Usage

HTTP requests made from a script are subject to well known restrictions, the most prominent being the same domain policy.

Firefox 3.5 introduced support for W3C’s Access Control for Cross-Site Requests specification, which requires a compliant client (for example, Firefox 3.5) and a compliant server (via this servlet filter).

This filter implements the required bits to support the server-side contract of the specification, and will allow a compliant client to perform cross-domain requests via the standard XMLHttpRequest object. If the client does not issue a compliant cross-domain request, this filter does nothing, and its overhead is the check of the presence of the cross-domain HTTP header.

This is extremely useful in CometD web applications where it is now possible to perform cross-domain long polling without using script injection (also known as the JSONP transport), and therefore removing all the downsides that the JSONP transport has (it’s chattier, does not react quickly to failures, has a message size limit, uses GET instead of POST, etc.).

Setup

You will need to put the jetty-servlets.jar file onto your classpath. If you are creating a webapp, ensure that this jar is included in your webapp’s WEB-INF/lib. Or, if you are running Jetty embedded you will need to ensure that jetty-servlets.jar is on the execution classpath. You can download the jetty-servlets.jar from the Maven Central Repository at https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-servlets/. It is also available as part of the Jetty distribution in the $JETTY_HOME/lib directory.

Configuration

This is a regular servlet filter that must be configured in web.xml.

It supports the following configuration parameters:

allowedOrigins

A comma separated list of origins that are allowed to access the resources. Default value is: * (all origins)

allowedMethods

A comma separated list of HTTP methods that are allowed to be used when accessing the resources. Default value is: GET,POST,HEAD

allowedHeaders

A comma separated list of HTTP headers that are allowed to be specified when accessing the resources. Default value is: X-Requested-With,Content-Type,Accept,Origin

allowCredentials

A boolean indicating if the resource allows requests with credentials. Default value is: true

preflightMaxAge

The number of seconds that preflight requests can be cached by the client. Default value is 1800 seconds (30 minutes)

chainPreflight

If true preflight requests are chained to their target resource for normal handling (as an OPTION request). Otherwise the filter will response to the preflight. Default is true.

exposedHeaders

A comma separated list of HTTP headers that are allowed to be exposed on the client. Default value is the empty list.

A typical configuration could be:

<web-app>

    <filter>
        <filter-name>cross-origin</filter-name>
        <filter-class>org.eclipse.jetty.ee9.servlets.CrossOriginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>cross-origin</filter-name>
        <url-pattern>/cometd/*</url-pattern>
    </filter-mapping>

</web-app>

Resource Handler

Info

Usage

This handler will serve static content and handle If-Modified-Since headers and is suitable for simple serving of static content.

There is no caching done with this handler, so if you are looking for a more fully featured way of serving static content look to the Default Servlet.
Requests for resources that do not exist are let pass (Eg no 404’s).

Improving the Look and Feel

The resource handler has a default stylesheet which you can change by calling setStyleSheet(String location) with the location of a file on the system that it can locate through the resource loading system. The default css is called jetty-dir.css and is located in the jetty-util package, pulled as a classpath resource from the jetty-util jar when requested through the ResourceHandler.

Embedded Example

The following is an example of a split fileserver, able to serve static content from multiple directory locations. Since this handler does not return 404’s on content you are able to iteratively try multiple resource handlers to resolve content.

Unresolved directive in extras/resource-handler.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/SplitFileServer.java[]

Debug Handler

Info

Usage

A simple handler that is useful to debug incoming traffic. It will log entry and exit points of HTTP requests as well as the response code.

Usage in Standard Distribution

The debug handler can be added to Jetty by activating the debug module.

Embedded usage

Server server = new Server(8080);
RolloverFileOutputStream outputStream = new RolloverFileOutputStream("MeinLogPfad/yyyy_mm_dd.request.log", true,10);

DebugHandler debugHandler = new DebugHandler();
debugHandler.setOutputStream(outputStream);
debugHandler.setHandler(server.getHandler());

server.setHandler(debugHandler);
server.start();

Example output

15:14:05.838:qtp551889550-13-selector-0 OPENED HttpConnection@e910ee4{IDLE},g=HttpGenerator{s=START},p=HttpParser{s=START,0 of 0}
15:14:05.846:qtp551889550-57:http://0:0:0:0:0:0:0:1:8080/ REQUEST 0:0:0:0:0:0:0:1 GET __utma=111872281.10102721.1321534299.1369833564.1370447492.35; __utmz=111872281.1321534299.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _opt_vi_RPY720HZ=75E12E63-0CD0-4D6F-8383-C90D5C8397C7; Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0
15:14:05.894:qtp551889550-57:http://0:0:0:0:0:0:0:1:8080/ RESPONSE 200 null
15:14:05.959:qtp551889550-59:http://0:0:0:0:0:0:0:1:8080/jetty.css REQUEST 0:0:0:0:0:0:0:1 GET __utma=111872281.10102721.1321534299.1369833564.1370447492.35; __utmz=111872281.1321534299.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _opt_vi_RPY720HZ=75E12E63-0CD0-4D6F-8383-C90D5C8397C7; visited=yes; Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0
15:14:05.962:qtp551889550-59:http://0:0:0:0:0:0:0:1:8080/jetty.css RESPONSE 200 null
15:14:06.052:qtp551889550-57:http://0:0:0:0:0:0:0:1:8080/images/jetty-header.jpg REQUEST 0:0:0:0:0:0:0:1 GET __utma=111872281.10102721.1321534299.1369833564.1370447492.35; __utmz=111872281.1321534299.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _opt_vi_RPY720HZ=75E12E63-0CD0-4D6F-8383-C90D5C8397C7; visited=yes; Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0
15:14:06.055:qtp551889550-57:http://0:0:0:0:0:0:0:1:8080/images/jetty-header.jpg RESPONSE 200 null
15:14:07.248:qtp551889550-59:http://0:0:0:0:0:0:0:1:8080/favicon.ico REQUEST 0:0:0:0:0:0:0:1 GET __utma=111872281.10102721.1321534299.1369833564.1370447492.35; __utmz=111872281.1321534299.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _opt_vi_RPY720HZ=75E12E63-0CD0-4D6F-8383-C90D5C8397C7; visited=yes; Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0
15:14:07.251:qtp551889550-59:http://0:0:0:0:0:0:0:1:8080/favicon.ico RESPONSE 404 text/html;charset=ISO-8859-1
15:14:09.330:qtp551889550-57 CLOSED HttpConnection@e910ee4{INTERESTED},g=HttpGenerator{s=START},p=HttpParser{s=START,0 of -1}

Statistics Handler

Info

Usage

Jetty currently has two main statistics collection mechanisms:

  • Instances of ConnectionStatistics can collect statistics for each connection of a connector.

  • The StatisticsHandler class may be used to collect statistics for HTTP requests.

The StatisticsHandler and ConnectionStatistics are not included in the default Jetty configuration, these need to be configured manually or enabled using the Jetty stats module on the command line.

$ java -jar {$jetty.home}/start.jar --add-to-start=stats

In addition to these, the SessionHandler and DefaultSessionCache classes collect statistics for sessions. These statistics are enabled by default and are accessible via JMX interface.

To view statistics, you have to be able to connect to Jetty using either JConsole or some other JMX agent. See [using-jmx] for more information.

Request Statistics

To collect request statistics a StatisticsHandler must be configured as one of the handlers of the server. Typically this can be done as the top level handler, but you may choose to configure a statistics handler for just one context by creating a context configuration file. You can enable the StatisticsHandler by activating the stats modules on the command line.

Alternately, if you are making multiple changes to the Jetty configuration, you could include statistics handler configuration into your own Jetty xml configuration. The following fragment shows how to configure a top level statistics handler:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  <Call name="insertHandler">
    <Arg>
      <New id="StatisticsHandler" class="org.eclipse.jetty.server.handler.StatisticsHandler"/>
    </Arg>
  </Call>
</Configure>

Connection Statistics

Detailed statistics on connection duration and number of messages are only collated when a connection is closed. The current and maximum number of connections are the only "live" statistics.

The following example shows how to turn on connection statistics in the Jetty XML format.

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  <Call name="addBeanToAllConnectors">
    <Arg>
      <New class="org.eclipse.jetty.io.ConnectionStatistics"/>
    </Arg>
  </Call>
</Configure>

A special variant of ConnectionStatistics called IncludeExcludeConnectionStatistics allows you to refine which types of connection you want to collect statistics for.

The following example shows how this can be used to record statistics only for WebSocket connections.

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  <Call name="addBeanToAllConnectors">
    <Arg>
      <New class="org.eclipse.jetty.io.IncludeExcludeConnectionStatistics">
        <Call name="include" arg="org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection"/>
      </New>
    </Arg>
  </Call>
</Configure>

Session Statistics

Session handling is built into Jetty for any servlet or webapp context. Detailed statistics on session duration are only collated when a session is closed. The current, minimum, and maximum number of sessions are the only "live" statistics. The session statistics are enabled by default and do not need to be configured.

InetAccess Handler

Info

Usage

Controls access to the wrapped handler using the real remote IP. Control is provided by and IncludeExcludeSet over a InetAddressSet. This handler uses the real internet address of the connection, not one reported in the forwarded for headers, as this cannot be as easily forged.

Usage in Standard Distribution

The InetAccess handler can be added to Jetty by activating the inetaccess module.

Moved Context Handler

Info

Usage

You can use the MovedContextHandler to relocate or redirect a context that has changed context path and/or virtual hosts.

You can configure it to permanently redirect the old URL to the new URL, in which case Jetty sends a Http Status code of 301 to the browser with the new URL. Alternatively, you can make it non-permanent, in which case Jetty sends a 302 Http Status code along with the new URL.

In addition, as with any other context, you can configure a list of virtual hosts, meaning that this context responds only to requests to one of the listed host names.

Suppose you have a context deployed at /foo, but that now you want to deploy at the root context / instead.

  • First you reconfigure and redeploy the context on Jetty.

  • Next you need a way to redirect all the browsers who have bookmarked /foo to the new path. You create a new context xml file in {$jetty/.base}/webapps and configure the MovedContextHandler to do the redirection from /foo to /.

Below is an example. This is a permanent redirection, which also preserves pathinfo and query strings on the redirect:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.server.handler.MovedContextHandler">
  <Set name="contextPath">/foo</Set>
  <Set name="newContextURL">/</Set>
  <Set name="permanent">true</Set>
  <Set name="discardPathInfo">false</Set>
  <Set name="discardQuery">false</Set>

  <Set name="virtualHosts">
    <Array type="String">
          <Item>209.235.245.73</Item>
          <Item>127.0.0.73</Item>
          <Item>acme.org</Item>
          <Item>www.acme.org</Item>
          <Item>server.acme.org</Item>
    </Array>
  </Set>
</Configure>

Shutdown Handler

Info

Usage

A handler that shuts the server down on a valid request. This is used to perform "soft" restarts from Java. If _exitJvm is set to true a hard System.exit() call is being made.

This is an example of how you can setup this handler directly with the Server. It can also be added as a part of handler chain or collection.

    Server server = new Server(8080);
    HandlerList handlers = new HandlerList();
    handlers.setHandlers(new Handler[]
    { someOtherHandler, new ShutdownHandler(server,"secret password") });
    server.setHandler(handlers);
    server.start();

This is an example that you can use to call the shutdown handler from within java.

   public static void attemptShutdown(int port, String shutdownCookie) {
        try {
            URL url = new URL("http://localhost:" + port + "/shutdown?token=" + shutdownCookie);
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.setRequestMethod("POST");
            connection.getResponseCode();
            logger.info("Shutting down " + url + ": " + connection.getResponseMessage());
        } catch (SocketException e) {
            logger.debug("Not running");
            // Okay - the server is not running
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

Default Handler

Info

Usage

A simple handler that is useful to terminate handler chains with a clean fashion. As in the example below, if a resource to be served is not matched within the resource handler the DefaultHandler will take care of producing a 404 page. This class is a useful template to either extend and embrace or simply provide a similar implementation for customizing to your needs. There is also an Error Handler that services errors related to the servlet api specification, so it is best to not get the two confused.

The DefaultHandler will also handle serving out the favicon.ico file should a request make it through all of the other handlers without being resolved.
    Server server = new Server(8080);
    ResourceHandler resourceHandler = new ResourceHandler();
    resourceHandler.setBaseResource(ResourceFactory.of(resourceHandler).newResource("."));
    Handler.Sequence handlers = new Handler.Sequence(
        resourceHandler, new DefaultHandler()
    );
    server.setHandler(handlers);
    server.start();

Error Handler

Info

Usage

A handler that is used to report errors from servlet contexts and webapp contexts to report error conditions. Primarily handles setting the various servlet spec specific response headers for error conditions. Can be customized by extending; for more information on this see Creating Custom Error Pages.

Rewrite Handler

The RewriteHandler matches a request against a set of rules, and modifies the request accordingly for any rules that match. The most common use is to rewrite request URIs, but it is capable of much more: rules can also be configured to redirect the response, set a cookie or response code on the response, modify the header, etc.

Info

The standard Jetty distribution bundle contains the jetty-rewrite module, so all you need to do is to enable it using one of the module commands, eg:

$ java -jar start.jar --add-to-start=rewrite
If you are running the standard Jetty distribution with the sample test webapp, there will be a demo of the rewrite module at http://localhost:8080/test/rewrite/

Usage

The rewrite module enables the following Jetty xml config file on the execution path:

Unresolved directive in extras/rewrite-handler.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../jetty-rewrite/src/main/config/etc/jetty-rewrite.xml[]

As the commented out code shows, you configure the RewriteHandler by adding various rules.

There is an example of rules configuration in the standard distribution in the demo-base/etc/demo-rewrite-rules.xml file:

Unresolved directive in extras/rewrite-handler.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../demos/demo-jetty-webapp/src/main/config/modules/demo.d/demo-rewrite-rules.xml[]
Embedded Example

This is an example for embedded Jetty, which does something similar to the configuration file example above:

  Server server = new Server();

  RewriteHandler rewrite = new RewriteHandler();
  rewrite.setRewriteRequestURI(true);
  rewrite.setRewritePathInfo(false);
  rewrite.originalPathAttribute("requestedPath");

  RedirectPatternRule redirect = new RedirectPatternRule();
  redirect.setPattern("/redirect/*");
  redirect.setReplacement("/redirected");
  rewrite.addRule(redirect);

  RewritePatternRule oldToNew = new RewritePatternRule();
  oldToNew.setPattern("/some/old/context");
  oldToNew.setReplacement("/some/new/context");
  rewrite.addRule(oldToNew);

  RewriteRegexRule reverse = new RewriteRegexRule();
  reverse.setRegex("/reverse/([^/]*)/(.*)");
  reverse.setReplacement("/reverse/$2/$1");
  rewrite.addRule(reverse);

  server.setHandler(rewrite);

Rules

There are several types of rules that are written extending useful base rule classes.

PatternRule

Matches against the request URI using the servlet pattern syntax.

CookiePatternRule

Adds a cookie to the response.

HeaderPatternRule

Adds/modifies a header in the response.

RedirectPatternRule

Redirects the response.

ResponsePatternRule

Sends the response code (status or error).

RewritePatternRule

Rewrite the URI by replacing the matched request path with a fixed string.

RegexRule

Matches against the request URI using regular expressions.

RedirectRegexRule

Redirect the response.

RewriteRegexRule

Rewrite the URI by matching with a regular expression. (The replacement string may use Template:$n to replace the nth capture group.)

HeaderRule

Match against request headers. Match either on a header name and specific value, or on the presence of a header (with any value).

ForwardedSchemaHeaderRule

Set the scheme on the request (defaulting to HTTPS).

Others

Extra rules that defy standard classification.

MsieSslRule

Disables the keep alive for SSL from IE5 or IE6.

LegacyRule

Implements the legacy API of RewriteHandler

RuleContainer

Groups rules together. The contained rules will only be processed if the conditions for the RuleContainer evaluate to true.

VirtualHostRuleContainer

Groups rules that apply only to a specific virtual host or a set of virtual hosts

Unresolved directive in index.adoc - include::fastcgi/chapter.adoc[]

Frameworks

CDI

Contexts and Dependency Injection for Java EE (CDI) is a standard implemented by frameworks such as Weld and Apache OpenWebBeans. This is a common way to assemble and configure webapplications by a process often referred to as 'decoration'.

Jetty integration of CDI frameworks allows CDI to be used to inject the Filters, Servlets and Listeners created within a Servlet Context. There are two approaches to integration:

  • CDI implementation can integrate with Jetty. This requires the CDI implementation to have Jetty specific code. Since Jetty-9.4.20 a loosely bound mechanism has been available for CDI implementations to extends the Jetty DecoratedObjectFactory without hard API dependencies. Prior to that, CDI implementations directly called jetty APIs that need to be explicitly exposed to the webapp.

  • Alternately, Jetty can integrate with CDI implementations by using standard CDI SPIs.

Jetty CDI Modules

The Jetty distribution come with several CDI modules. These modules do not provide CDI, but instead enable one of more integration mechanisms.

Jetty cdi Module

The cdi module supports either two modes of CDI integration which can be selected either by the "org.eclipse.jetty.ee9.cdi" context init parameter or the "org.eclipse.jetty.ee9.cdi" server attribute (which is initialised from the "jetty.cdi.mode" start property). Supported modes are:

  • CdiSpiDecorator Jetty will call the CDI SPI within the webapp to decorate objects (default).

  • CdiDecoratingLister The webapp may register a decorator on the context attribute "org.eclipse.jetty.ee9.cdi.decorator".

cd $JETTY_BASE
java -jar $JETTY_HOME/start.jar --add-to-start=cdi
Jetty cdi-decorate Module

This module depends on the cdi module and sets the default mode to CdiDecoratingListener. This is the preferred mode for Weld integration.

cd $JETTY_BASE
java -jar $JETTY_HOME/start.jar --add-to-start=cdi-decorate
Jetty cdi-spi Module

This module depends on the cdi module and sets the default mode to CdiSpiDecorator. This is the preferred mode for Open Web Beans integration.

cd $JETTY_BASE
java -jar $JETTY_HOME/start.jar --add-to-start=cdi-spi
Jetty cdi2 Module

This module supports the deprecated technique of exposing private Jetty decorate APIs to the CDI implementation in the webapp.

cd $JETTY_BASE
java -jar $JETTY_HOME/start.jar --add-to-start=cdi2

This module is equivalent to directly modifying the class path configuration with a jetty-web.xml like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://eclipse.dev/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
   <Call name="prependServerClass">
      <Arg>-org.eclipse.jetty.util.Decorator</Arg>
   </Call>
   <Call name="prependServerClass">
      <Arg>-org.eclipse.jetty.util.DecoratedObjectFactory</Arg>
   </Call>
   <Call name="prependServerClass">
      <Arg>-org.eclipse.jetty.server.handler.ContextHandler.</Arg>
   </Call>
   <Call name="prependServerClass">
      <Arg>-org.eclipse.jetty.server.handler.ContextHandler</Arg>
   </Call>
   <Call name="prependServerClass">
      <Arg>-org.eclipse.jetty.ee9.servlet.ServletContextHandler</Arg>
   </Call>
</Configure>
The cdi2 module or directly modifying the web application classpath will not work for Jetty 10.0.0 and later. It should only be used for versions prior to Jetty 9.4.20 and/or Weld 3.1.2.Final

Embedded Jetty with CDI

When starting embedded Jetty programmatically from the main method, to use CDI it may be necessary:

  • enable a Jetty CDI integration mode

  • and/or enable a CDI frame integration.

However, depending on the exact configuration of the embedded server, either or both steps may not be required as `ServletContainerInitializer`s may be discovered.

The details for embedding CDI is explained in the Embedded Jetty with Weld section, which can also be adapted to other CDI frameworks. Unresolved directive in frameworks/chapter.adoc - include::weld.adoc[]

OSGI

Introduction

The Jetty OSGi infrastructure provides a Jetty container inside an OSGi container. Traditional JavaEE webapps can be deployed, in addition to Jetty ContextHandlers, along with OSGi web bundles. In addition, the infrastructure also supports the OSGi HttpService interface.

General Setup

All of the Jetty jars contain manifest entries appropriate to ensure that they can be deployed into an OSGi container as bundles. You will need to install some jetty jars into your OSGi container. You can always find the Jetty jars either in the Maven Central repository, or you can download a distribution of Jetty. Here’s the absolute minimal set of Jetty jars:

Table 7. Minimal Bundles
Jar Bundle Symbolic Name

jetty-util

org.eclipse.jetty.util

jetty-http

org.eclipse.jetty.http

jetty-io

org.eclipse.jetty.io

jetty-security

org.eclipse.jetty.security

jetty-server

org.eclipse.jetty.server

jetty-servlet

org.eclipse.jetty.servlet

jetty-webapp

org.eclipse.jetty.webapp

jetty-deploy

org.eclipse.jetty.deploy

jetty-xml

org.eclipse.jetty.xml

jetty-jakarta-servlet-api

org.eclipse.jetty.servlet-api

You must also install the Apache Aries SPI Fly bundles as many parts of Jetty - for example ALPN, websocket, annotations - use the ServiceLoader mechanism, which requires an OSGi Service Loader Mediator like SPI Fly:

Table 8. SPI Fly Bundles
Jar Bundle Symbolic Name Location

org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle-1.2.4.jar

org.apache.aries.spifly.dynamic.bundle

Maven central

We strongly recommend that you also deploy the annotation-related jars also, as the Servlet Specification increasingly relies on annotations for functionality.

You will also need the OSGi Event Management service and the OSGi Configuration Management service. If your OSGi container does not automatically make these available, you will need to add them in a way appropriate to your container.

The Jetty OSGi Container

The jetty-osgi-boot jar

Now that you have the basic set of Jetty jars installed, you can install the jetty-osgi-boot.jar bundle, downloadable from the maven central repo here.

This bundle will instantiate and make available the Jetty OSGi container when it is started. If this bundle is not auto-started upon installation into your OSGi container, you should start it manually using a command appropriate for your container.

Customizing the Jetty Container

Before going ahead with the install, you may want to customize the Jetty container. In general this is done by a combination of System properties and the usual Jetty xml configuration files. The way you define the System properties will depend on which OSGi container you are using, so ensure that you are familiar with how to set them for your environment. In the following examples, we will assume that the OSGi container allows us to set System properties as simple name=value pairs.

The available System properties are:

jetty.http.port

If not specified, this defaults to the usual jetty port of 8080.

jetty.home

Either this property or the jetty.home.bundle must be specified. This property should point to a file system location that has an etc/ directory containing xml files to configure the Jetty container on startup. For example:

jetty.home=/opt/custom/jetty

Where /opt/custom/jetty contains:

etc/jetty.xml
etc/jetty-selector.xml
etc/jetty-deployer.xml
etc/jetty-special.xml
jetty.home.bundle

Either this property or the jetty.home property must be specified. This property should specify the symbolic name of a bundle which contains a directory called jettyhome/. The jettyhome/ directory should have a subdirectory called etc/ that contains the xml files to be applied to Jetty on startup. The jetty-osgi-boot.jar contains a jettyhome/ directory with a default set of xml configuration files. Here’s how you would specify it:

jetty.home.bundle=org.eclipse.jetty.ee9.osgi.boot

Here’s a partial listing of that jar that shows you the names of the xml files contained within it:

META-INF/MANIFEST.MF
jettyhome/etc/jetty.xml
jettyhome/etc/jetty-deployer.xml
jettyhome/etc/jetty-http.xml
jetty.etc.config.urls

This specifies the paths of the xml files that are to be used. If not specified, they default to:

etc/jetty.xml,etc/jetty-http.xml,etc/jetty-deployer.xml

Note that the paths can either be relative or absolute, or a mixture. If the path is relative, it is resolved against either jetty.home or jetty.home.bundle, whichever was specified. You can use this ability to mix and match jetty configuration files to add functionality, such as adding in a https connector. Here’s an example of adding a HTTPS connector, using the relevant files from the jetty-home:

etc/jetty.xml, etc/jetty-http.xml, /opt/jetty/etc/jetty-ssl.xml, /opt/jetty/etc/jetty-https.xml, etc/jetty-deployer.xml

Note that regardless of whether you set the jetty.home or jetty.home.bundle property, when Jetty executes the configuration files, it will set an appropriate value for jetty.home so that references in xml files to <property name="jetty.home"> will work. Be careful, however, if you are mixing and matching relative and absolute configuration file paths: the value of jetty.home is determined from the resolved location of the relative files only.

The Jetty Container as an OSGi Service

You can now go ahead and deploy the jetty-osgi-boot.jar into your OSGi container. A Jetty server instance will be created, the xml config files applied to it, and then published as an OSGi service. Normally, you will not need to interact with this service instance, however you can retrieve a reference to it using the usual OSGi API:

org.osgi.framework.BundleContext bc;
org.osgi.framework.ServiceReference ref = bc.getServiceReference("org.eclipse.jetty.server.Server");

The Server service has a couple of properties associated with it that you can retrieve using the org.osgi.framework.ServiceReference.getProperty(String) method:

managedServerName

The Jetty Server instance created by the jetty-osgi-boot.jar will be called "defaultJettyServer"

jetty.etc.config.urls

The list of xml files resolved from either jetty.home or jetty.home.bundle/jettyhome

Adding More Jetty Servers

As we have seen in the previous section, the jetty-osgi-boot code will create an org.eclipse.jetty.server.Server instance, apply the xml configuration files specified by jetty.etc.config.urls System property to it, and then register it as an OSGi Service. The name associated with this default instance is defaultJettyServer.

You can create other Server instances, register them as OSGi Services, and the jetty-osgi-boot code will notice them, and configure them so that they can deploy ContextHandlers and webapp bundles. When you deploy webapps or ContextHandlers as bundles or Services (see sections below) you can target them to be deployed to a particular server instance via the Server’s name.

Here’s an example of how to create a new Server instance and register it with OSGi so that the jetty-osgi-boot code will find it and configure it so it can be a deployment target:

public class Activator implements BundleActivator
{

    public void start(BundleContext context) throws Exception
    {

        Server server = new Server();
        //do any setup on Server in here
        String serverName = "fooServer";
        Dictionary serverProps = new Hashtable();
        //define the unique name of the server instance
        serverProps.put("managedServerName", serverName);
        serverProps.put("jetty.http.port", "9999");
        //let Jetty apply some configuration files to the Server instance
        serverProps.put("jetty.etc.config.urls", "file:/opt/jetty/etc/jetty.xml,file:/opt/jetty/etc/jetty-selector.xml,file:/opt/jetty/etc/jetty-deployer.xml");
        //register as an OSGi Service for Jetty to find
        context.registerService(Server.class.getName(), server, serverProps);

    }
}

Now that we have created a new Server called "fooServer", we can deploy webapps and ContextHandlers as Bundles or Services to it (see below for more information on this). Here’s an example of deploying a webapp as a Service and targeting it to the "fooServer" Server we created above:

public class Activator implements BundleActivator
{

    public void start(BundleContext context) throws Exception
    {

        //Create a webapp context as a Service and target it at the "fooServer" Server instance
        WebAppContext webapp = new WebAppContext();
        Dictionary props = new Hashtable();
        props.put("war",".");
        props.put("contextPath","/acme");
        props.put("managedServerName", "fooServer");
        context.registerService(ContextHandler.class.getName(),webapp,props);
    }
}

Deploying Bundles as Webapps

The Jetty OSGi container listens for the installation of bundles, and will automatically attempt to deploy any that appear to be webapps.

Any of the following criteria are sufficient for Jetty to deploy the bundle as a webapp:

Bundle contains a WEB-INF/web.xml file

If the bundle contains a web descriptor, then it is automatically deployed. This is an easy way to deploy classic JavaEE webapps.

Bundle MANIFEST contains Jetty-WarFolderPath (for releases prior tojetty-9.3) or Jetty-WarResourcePath

This is the location within the bundle of the webapp resources. Typically this would be used if the bundle is not a pure webapp, but rather the webapp is a component of the bundle. Here’s an example of a bundle where the resources of the webapp are not located at the root of the bundle, but rather inside the subdirectory web/ :

MANIFEST:

Bundle-Name: Web
Jetty-WarResourcePath: web
Import-Package: jakarta.servlet;version="3.1",
 jakarta.servlet.resources;version="3.1"
Bundle-SymbolicName: com.acme.sample.web

Bundle contents:

META-INF/MANIFEST.MF
web/index.html
web/foo.html
web/WEB-INF/web.xml
com/acme/sample/web/MyStuff.class
com/acme/sample/web/MyOtherStuff.class
Bundle MANIFEST contains Web-ContextPath

This header can be used in conjunction with either of the two preceding headers to control the context path to which the webapp is deployed, or alone to identify that the bundle’s contents should be published as a webapp. This header is part of the RFC-66 specification for using webapps with OSGi. Here’s an example based on the previous one where we use the Web-ContextPath header to set its deployment context path to be "/sample" :

MANIFEST:

Bundle-Name: Web
Jetty-WarResourcePath: web
Web-ContextPath: /sample
Import-Package: jakarta.servlet;version="3.1",
 jakarta.servlet.resources;version="3.1"
Bundle-SymbolicName: com.acme.sample.web

You can also define extra headers in your bundle MANIFEST that help customize the web app to be deployed:

Jetty-defaultWebXmlFilePath

The location of a webdefault.xml file to apply to the webapp. The location can be either absolute (either absolute path or file: url), or relative (in which case it is interpreted as relative to the bundle root). Defaults to the webdefault.xml file built into the Jetty OSGi container.

Jetty-WebXmlFilePath

The location of the web.xml file. The location can be either absolute (either absolute path or file: url), or relative (in which case it is interpreted as relative to the bundle root). Defaults to WEB-INF/web.xml

Jetty-extraClassPath

A classpath of additional items to add to the webapp’s classloader.

Jetty-bundleInstall

The path to the base folder that overrides the computed bundle installation - mostly useful for those OSGi frameworks that unpack bundles by default.

Require-TldBundle

A comma separated list of bundle symbolic names of bundles containing TLDs that this webapp depends upon.

managedServerName

The name of the Server instance to which to deploy this webapp bundle. If not specified, defaults to the default Server instance called "defaultJettyServer".

Jetty-WarFragmentResourcePath

The path within a fragment hosted by the web-bundle that contains static resources for the webapp. The path is appended to the base resource for the webapp (see Jetty-WarResourcePath).

Jetty-WarPrependFragmentResourcePath

The path within a fragment hosted by the web-bundle that contains static resources for the webapp. The path is prepended to the base resource for the webapp (see Jetty-WarResourcePath).

Jetty-ContextFilePath

A comma separated list of paths within the webapp bundle to Jetty context files that will be applied to the webapp. Alternatively you may include a single Jetty context file called jetty-webapp-context.xml in the webapp bundle’s META-INF directory and it will be automatically applied to the webapp.

Determining the Context Path for a Webapp Bundle

As we have seen in the previous section, if the bundle MANIFEST contains the RFC-66 header Web-ContextPath, Jetty will use that as the context path. If the MANIFEST does not contain that header, then Jetty will concoct a context path based on the last element of the bundle’s location (by calling Bundle.getLocation()) after stripping off any file extensions.

For example, suppose we have a bundle whose location is:

file://some/where/over/the/rainbow/oz.war

The corresponding synthesized context path would be:

/oz
Extra Properties Available for Webapp Bundles

You can further customize your webapp by including a Jetty context xml file that is applied to the webapp. This xml file must be placed in META-INF of the bundle, and must be called jetty-webapp-context.xml.

Here’s an example of a webapp bundle listing containing such a file:

META-INF/MANIFEST.MF
META-INF/jetty-webapp-context.xml
web/index.html
web/foo.html
web/WEB-INF/web.xml
com/acme/sample/web/MyStuff.class
com/acme/sample/web/MyOtherStuff.class

Here’s an example of the contents of a META-INF/jetty-webapp-context.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="defaultsDescriptor"><Property name="bundle.root"/>META-INF/webdefault.xml</Set>
</Configure>

As you can see, it is a normal context xml file used to set up a webapp. There are, however, some additional useful properties that can be referenced

Server

This is a reference to the Jetty org.eclipse.jetty.server.Server instance to which the webapp being configured in the context xml file will be deployed.

bundle.root

This is a reference to the org.eclipse.jetty.util.resource.Resource that represents the location of the Bundle. Note that this could be either a directory in the file system if the OSGi container automatically unpacks bundles, or it may be a jar:file: url if the bundle remains packed.

Deploying Bundles as Jetty ContextHandlers

In addition to deploying webapps, the Jetty OSGi container listens for the installation of bundles that are not heavyweight webapps, but rather use the flexible Jetty-specific concept of ContextHandlers.

The following is the criteria used to decide if a bundle can be deployed as a ContextHandler:

Bundle MANIFEST contains Jetty-ContextFilePath

A comma separated list of names of context files - each one of which represents a ContextHandler that should be deployed by Jetty. The context files can be inside the bundle, external to the bundle somewhere on the file system, or external to the bundle in the jetty.home directory.

A context file that is inside the bundle:

Jetty-ContextFilePath: ./a/b/c/d/foo.xml

A context file that is on the file system:

Jetty-ContextFilePath: /opt/app/contexts/foo.xml

A context file that is relative to jetty.home:

Jetty-ContextFilePath: contexts/foo.xml

A number of different context files:

Jetty-ContextFilePath: ./a/b/c/d/foo.xml,/opt/app/contexts/foo.xml,contexts/foo.xml

Other MANIFEST properties that can be used to configure the deployment of the ContextHandler:

managedServerName

The name of the Server instance to which to deploy this webapp bundle. If not specified, defaults to the default Server instance called "defaultJettyServer".

Determining the Context Path for a ContextHandler Bundle

Usually, the context path for the ContextHandler will be set by the context xml file. However, you can override any path set in the context xml file by using the Web-ContextPath header in the MANIFEST.

Extra Properties Available for Context Xml Files

Before the Jetty OSGi container applies a context xml file found in a Jetty-ContextFilePath MANIFEST header, it sets a few useful propertiesthat can be referred to within the xml file:

Server

This is a reference to the Jetty org.eclipse.jetty.server.Server instance to which the ContextHandler being configured in the context xml file will be deployed.

bundle.root

This is a reference to the org.eclipse.jetty.util.resource.Resource that represents the location of the Bundle (obtained by calling Bundle.getLocation()). Note that this could be either a directory in the file system if the OSGi container automatically unpacks bundles, or it may be a jar:file: url if the bundle remains packed.

Here’s an example of a context xml file that makes use of these properties:

Unresolved directive in frameworks/osgi.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml[]

Deploying Services as Webapps

In addition to listening for bundles whose format or MANIFEST entries define a webapp or ContextHandler for to be deployed, the Jetty OSGi container also listens for the registration of OSGi services that are instances of org.eclipse.jetty.ee9.webapp.WebAppContext. So you may programmatically create a WebAppContext, register it as a service, and have Jetty pick it up and deploy it.

Here’s an example of doing that with a simple bundle that serves static content, and an org.osgi.framework.BundleActivator that instantiates the WebAppContext:

The bundle contents:

META-INF/MANIFEST.MF
index.html
com/acme/osgi/Activator.class

The MANIFEST.MF:

Bundle-Classpath: .
Bundle-Name: Jetty OSGi Test WebApp
DynamicImport-Package: org.eclipse.jetty.*;version="[9.0,10.0)"
Bundle-Activator: com.acme.osgi.Activator
Import-Package: org.eclipse.jetty.server.handler;version="[9.0,10)",
 org.eclipse.jetty.webapp;version="[9.0,10)",
 org.osgi.framework;version= "[1.5,2)",
 org.osgi.service.cm;version="1.2.0",
 org.osgi.service.packag eadmin;version="[1.2,2)",
 org.osgi.service.startlevel;version="1.0.0",
 org.osgi.service.url;version="1.0.0",
 org.osgi.util.tracker;version= "1.3.0",
 org.xml.sax,org.xml.sax.helpers
Bundle-SymbolicName: com.acme.testwebapp

The Activator code:

public void start(BundleContext context) throws Exception
{
    WebAppContext webapp = new WebAppContext();
    Dictionary props = new Hashtable();
    props.put("Jetty-WarResourcePath",".");
    props.put("contextPath","/acme");
    context.registerService(WebAppContext.class.getName(),webapp,props);
}

The above setup is sufficient for Jetty to recognize and deploy the WebAppContext at /acme.

As the example shows, you can use OSGi Service properties in order to communicate extra configuration information to Jetty:

Jetty-WarFolderPath (for releases prior to 9.3) or Jetty-WarResourcePath

The location within the bundle of the root of the static resources for the webapp

Web-ContextPath

The context path at which to deploy the webapp.

Jetty-defaultWebXmlFilePath

The location within the bundle of a webdefault.xml file to apply to the webapp. Defaults to that of the Jetty OSGi container.

Jetty-WebXmlFilePath

The location within the bundle of the web.xml file. Defaults to WEB-INF/web.xml

Jetty-extraClassPath

A classpath of additional items to add to the webapp’s classloader.

Jetty-bundleInstall

The path to the base folder that overrides the computed bundle installation - mostly useful for those OSGi frameworks that unpack bundles by default.

Require-TldBundle

A comma separated list of bundle symbolic names of bundles containing TLDs that this webapp depends upon.

managedServerName

The name of the Server instance to which to deploy this webapp. If not specified, defaults to the default Server instance called "defaultJettyServer".

Jetty-WarFragmentResourcePath

The path within a fragment hosted by the web-bundle that contains static resources for the webapp. The path is appended to the base resource for the webapp (see Jetty-WarResourcePath).

Jetty-WarPrependFragmentResourcePath

The path within a fragment hosted by the web-bundle that contains static resources for the webapp. The path is prepended to the base resource for the webapp (see Jetty-WarResourcePath).

Deploying Services as ContextHandlers

Similarly to WebApp`Contexts, the Jetty OSGi container can detect the registration of an OSGi Service that represents a ContextHandler and ensure that it is deployed. The ContextHandler can either be fully configured before it is registered as an OSGi service - in which case the Jetty OSGi container will merely deploy it - or the ContextHandler can be partially configured, with the Jetty OSGi container completing the configuration via a context xml file and properties associated with the Service.

Here’s an example of doing that with a simple bundle that serves static content with an org.osgi.framework.BundleActivator that instantiates a ContextHandler and registers it as an OSGi Service, passing in properties that define a context xml file and context path for Jetty to apply upon deployment:

The bundle contents:

META-INF/MANIFEST.MF
static/index.html
acme.xml
com/acme/osgi/Activator.class
com/acme/osgi/Activator$1.class

The MANIFEST:

Bundle-Classpath: .
Bundle-Name: Jetty OSGi Test Context
DynamicImport-Package: org.eclipse.jetty.*;version="[9.0,10.0)"
Bundle-Activator: com.acme.osgi.Activator
Import-Package: jakarta.servlet;version="2.6.0",
 jakarta.servlet.resources;version="2.6.0",
 org.eclipse.jetty.server.handler;version="[9.0,10)",
 org.osgi.framework;version="[1.5,2)",
 org.osgi.service.cm;version="1.2.0",
 org.osgi.service.packageadmin;version="[1.2,2)",
 org.osgi.service.startlevel;version="1.0.0.o",
 org.osgi.service.url;version="1.0.0",
 org.osgi.util.tracker;version="1.3.0",
 org.xml.sax,org.xml.sax.helpers
Bundle-SymbolicName: com.acme.testcontext

The Activator code:

public void start(final BundleContext context) throws Exception
{
    ContextHandler ch = new ContextHandler();
    ch.addEventListener(new ServletContextListener () {

            @Override
            public void contextInitialized(ServletContextEvent sce)
            {
               System.err.println("Context is initialized");
            }

            @Override
            public void contextDestroyed(ServletContextEvent sce)
            {
                System.err.println("Context is destroyed!");
            }

    });
    Dictionary props = new Hashtable();
    props.put("Web-ContextPath","/acme");
    props.put("Jetty-ContextFilePath", "acme.xml");
    context.registerService(ContextHandler.class.getName(),ch,props);
}

The contents of the acme.xml context file:

Unresolved directive in frameworks/osgi.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml[]

You may also use the following OSGi Service properties:

managedServerName

The name of the Server instance to which to deploy this webapp. If not specified, defaults to the default Server instance called "defaultJettyServer".

Extra Properties Available for Context Xml Files

Before the Jetty OSGi container applies a context xml file found in a Jetty-ContextFilePath property, it sets a few useful properties that can be referred to within the xml file:

Server

This is a reference to the Jetty org.eclipse.jetty.server.Server instance to which the ContextHandler being configured in the context xml file will be deployed.

bundle.root

This is a reference to the org.eclipse.jetty.util.resource.Resource that represents the location of the Bundle publishing the ContextHandler as a Service (obtained by calling Bundle.getLocation()). Note that this could be either a directory in the file system if the OSGi container automatically unpacks bundles, or it may be a jar:file: url if the bundle remains packed.

In the example above, you can see both of these properties being used in the context xml file.

Support for the OSGi Service Platform Enterprise Specification

The Jetty OSGi container implements several aspects of the Enterprise Specification v4.2 for the WebAppContexts and ContextHandlers that it deploys from either bundles or OSGi services as outlined in foregoing sections.

Context Attributes

For each WebAppContext or ContextHandler, the following context attribute is set, as required by section 128.6.1 Bundle Context page 427:

osgi-bundleContext

The value of this attribute is the BundleContext representing the Bundle associated with the WebAppContext or ContextHandler.

Service Attributes

As required by the specification section 128.3.4 Publishing the Servlet Context page 421, each WebAppContext and ContextHandler deployed by the Jetty OSGi container is also published as an OSGi service (unless it has been already - see sections 1.6 and 1.7). The following properties are associated with these services:

osgi.web.symbolicname

The symbolic name of the Bundle associated with the WebAppContext or ContextHandler

osgi.web.version

The Bundle-Version header from the Bundle associated with the WebAppContext or ContextHandler

osgi.web.contextpath

The context path of the WebAppContext or ContextHandler

OSGi Events

As required by the specification section 128.5 Events pg 426, the following OSGi Event Admin events will be posted:

org/osgi/service/web/DEPLOYING

The Jetty OSGi container is about to deploy a WebAppContext or ContextHandler

org/osgi/service/web/DEPLOYED

The Jetty OSGi container has finished deploying a WebAppContext or ContextHandler and it is in service

org/osgi/service/web/UNDEPLOYING

The Jetty OSGi container is about to undeploy a WebAppContext or ContextHandler

org/osgi/service/web/UNDEPLOYED

The Jetty OSGi container has finished undeploying a WebAppContext or ContextHandler and it is no longer in service

org/osgi/service/web/FAILED

The Jetty OSGi container failed to deploy a WebAppContext or ContextHandler

Using JSPs

Setup

In order to use JSPs with your webapps and bundles you will need to install the JSP and JSTL jars and their dependencies into your OSGi container. Some you will find in the Jetty distribution, whereas others you will need to download from Maven central. Here is the list of recommended jars (NOTE the version numbers may change in future):

Table 9. Jars Required for JSP
Jar Bundle Symbolic Name Location

The annotation jars

org.mortbay.jasper:apache-el

org.mortbay.jasper.apache-el

Distribution lib/apache-jsp

org.mortbay.jasper:apache-jsp

org.mortbay.jasper.apache-jsp

Distribution lib/apache-jsp

org.eclipse.jetty:apache-jsp

org.eclipse.jetty.apache-jsp

Distribution lib/apache-jsp

org.eclipse.jdt.core-3.8.2.v20130121.jar

org.eclipse.jdt.core.compiler.batch

Distribution lib/apache-jsp

org.eclipse.jetty.osgi:jetty-osgi-boot-jsp

org.eclipse.jetty.ee9.osgi.boot.jsp

Maven central

  1. As of Jetty 9.2.3 the jetty-osgi-boot-jsp bundle changed to using Apache Jasper as the JSP implementation. Prior to this the Glassfish Jasper implementation was used, which had a different set of dependencies - pay careful attention to the jars listed both at the top of this page and in this section, as deployment of other jars can cause incomplete or incorrect package resolution in the OSGi container.

  2. The order of deployment is important. Deploy these bundles in the order shown or you may experience strange failures in the compilation of jsps. This can be hard to diagnose but is almost always caused by the ServletContainerInitializer in the org.eclipse.jetty.apache-jsp bundle for the jsp container not being invoked due to incorrect startup of the annotation jars.

For the JSTL library, we recommend the use of the implementation from Glassfish, as it has fewer dependencies:

Table 10. Jars Required for Glassfish JSTL
Jar Bundle Symbolic Name The jsp jars

jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api-2.0.0.jar

jakarta.servlet.jsp.jstl-api

The jetty-osgi-boot-jsp jar

To be able to use JSPs you will need to also install the jetty-osgi-boot-jsp.jar into your OSGi container. This jar can be obtained from maven central here.

This bundle acts as a fragment extension to the jetty-osgi-boot.jar and adds in support for using JSP.

Using TagLibs

The Jetty JSP OSGi container will make available the JSTL tag library to all webapps. If you only use this tag library, then your webapp will work without any further modification.

However, if you make use of other taglibs, you will need to ensure that they are installed into the OSGi container, and also define some System properties and/or MANIFEST headers in your webapp. This is necessary because the classloading regime used by the OSGi container is very different than that used by JSP containers, and the MANIFEST of a normal webapp does not contain enough information for the OSGi environment to allow a JSP container to find and resolve TLDs referenced in the webapp’s .jsp files.

Firstly, lets look at an example of a web bundle’s modified MANIFEST file so you get an idea of what is required. This example is a web bundle that uses the Spring servlet framework:

Bundle-SymbolicName: com.acme.sample
Bundle-Name: WebSample
Web-ContextPath: taglibs
Import-Bundle: org.springframework.web.servlet
Require-TldBundle: org.springframework.web.servlet
Bundle-Version: 1.0.0
Import-Package: org.eclipse.virgo.web.dm;version="[3.0.0,4.0.0)",org.s
 pringframework.context.config;version="[2.5.6,4.0.0)",org.springframe
 work.stereotype;version="[2.5.6,4.0.0)",org.springframework.web.bind.
 annotation;version="[2.5.6,4.0.0)",org.springframework.web.context;ve
 rsion="[2.5.6,4.0.0)",org.springframework.web.servlet;version="[2.5.6
 ,4.0.0)",org.springframework.web.servlet.view;version="[2.5.6,4.0.0)"

The Require-TldBundle header tells the Jetty OSGi container that this bundle contains TLDs that need to be passed over to the JSP container for processing. The Import-Bundle header ensures that the implementation classes for these TLDs will be available to the webapp on the OSGi classpath.

The format of the Require-TldBundle header is a comma separated list of one or more symbolic names of bundles containing TLDs.

Container Path Taglibs

Some TLD jars are required to be found on the Jetty OSGi container’s classpath, rather than considered part of the web bundle’s classpath. For example, this is true of JSTL and Java Server Faces. The Jetty OSGi container takes care of JSTL for you, but you can control which other jars are considered as part of the container’s classpath by using the System property org.eclipse.jetty.ee9.osgi.tldbundles:

org.eclipse.jetty.ee9.osgi.tldbundles

System property defined on the OSGi environment that is a comma separated list of symbolic names of bundles containing taglibs that will be treated as if they are on the container’s classpath for web bundles. For example:

org.eclipse.jetty.ee9.osgi.tldbundles=com.acme.special.tags,com.foo.web,org.bar.web.framework

You will still need to define the Import-Bundle header in the MANIFEST file for the web bundle to ensure that the TLD bundles are on the OSGi classpath.

Alternatively or additionally, you can define a pattern as a context attribute that will match symbolic bundle names in the OSGi environment containing TLDs that should be considered as discovered from the container’s classpath.

org.eclipse.jetty.server.webapp.containerIncludeBundlePattern

This pattern must be specified as a context attribute of the WebAppContext representing the web bundle. Unless you are deploying your own WebAppContext (see Deploying Services as Webapps), you won’t have a reference to the WebAppContext to do this. In that case, it can be specified on the org.eclipse.jetty.deploy.DeploymentManager, where it will be applied to every webapp deployed by the Jetty OSGi container. The jetty-osgi-boot.jar contains the default jettyhome/etc/jetty-deploy.xml file where the DeploymentManager is defined. To set the pattern, you will need to provide your own etc files - see the section on customizing the jetty container for how to do this. Here’s how the jetty-deploy.xml file would look if we defined a pattern that matched all bundle symbolic names ending in "tag" and "web":

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Call name="addBean">
      <Arg>
        <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
          <Set name="contexts">
            <Ref refid="Contexts" />
          </Set>
          <Call name="setContextAttribute">
            <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeBundlePattern</Arg>
            <Arg>.*\.tag$|.*\.web$</Arg>
          </Call>
        </New>
      </Arg>
    </Call>
</Configure>

Again, you will still need to define suitable Import-Bundle headers in your web bundle MANIFEST to ensure that bundles matching the pattern are available on the OSGi class path.

Using Annotations/ServletContainerInitializers

Annotations are very much part of the Servlet 3.0 and 3.1 specifications. In order to use them with Jetty in OSGi, you will need to deploy some extra jars into your OSGi container:

Table 11. Jars Required for Annotations
Jar Bundle Symbolic Name Location

The spifly jars

org.ow2.asm:asm-7.0.jar

org.objectweb.asm

Maven central

org.ow2.asm:asm-commons-7.0.jar

org.objectweb.asm.commons

Maven central

org.ow2.asm:asm-tree-7.0.jar

org.objectweb.asm.tree

Maven central

javax.annotation:javax.annotation-api-1.2.jar

javax.annotation-api

Maven central

jta api version 1.1.1 (eg org.apache.geronimo.specs:geronimo-jta_1.1_spec-1.1.1.jar)*

Maven central

javax mail api version 1.4.1 (eg org.eclipse.jetty.orbit:javax.mail.glassfish-1.4.1.v201005082020.jar)*

Maven central

jetty-jndi

org.eclipse.jetty.jndi

Distribution lib/

jetty-plus

org.eclipse.jetty.plus

Distribution lib/

jetty-annotations

org.eclipse.jetty.annotations

Distribution lib/

If you wish to use JSPs you will need to deploy these annotation-related jars.
You may be able to deploy later versions or other providers of these specifications, however these particular versions are known to have correct manifests and have been tested and known to work with OSGi.

Even if your webapp itself does not not use annotations, you may need to deploy these jars because your webapp depends on a Jetty module or a 3rd party library that uses a jakarta.servlet.ServletContainerInitializer. This interface requires annotation support. It is implemented by providers of code that extend the capabilities of the container. An example of this is the Jetty JSR356 Websocket implementation, although it is being used increasingly commonly in popular libraries like Spring, Jersey and JSP containers.

To find ServletContainerInitializers on the classpath, Jetty uses the Java ServiceLoader mechanism. For this to function in OSGi, you will need an OSGi R5 compatible container, and have support for the Service Loader Mediator. Jetty has been tested with the Aries SpiFly module, which is the reference implementation of the Service Loader Mediator, and is listed in the jars above.

OSGi Containers

Felix

The Jetty OSGi integration has been successfully tested against Felix 5.0.0.

You will require the following extra Felix services, available as separately downloadable jars:

Unfortunately, as of Felix 4.x there is a difficultly with the resolution of the javax.transaction package. A description of the problem and hint to solving it is described [here].

The simplest solution for this is to extract the default.properties file from the felix.jar, change the declaration of the javax.sql and javax.transaction packages and set the changed lines as the value of the org.osgi.framework.system.packages property in the conf/config.properties file.

The default.properties file defines the default org.osgi.framework.system.packages property like this:

# Default packages exported by system bundle.
org.osgi.framework.system.packages=org.osgi.framework; version=1.7.0, \
 org.osgi.framework.hooks.bundle; version=1.1.0, \
 org.osgi.framework.hooks.resolver; version=1.0.0, \
 org.osgi.framework.hooks.service; version=1.1.0, \
 org.osgi.framework.hooks.weaving; version=1.0.0, \
 org.osgi.framework.launch; version=1.1.0, \
 org.osgi.framework.namespace; version=1.0.0, \
 org.osgi.framework.startlevel; version=1.0.0, \
 org.osgi.framework.wiring; version=1.1.0, \
 org.osgi.resource; version=1.0.0, \
 org.osgi.service.packageadmin; version=1.2.0, \
 org.osgi.service.startlevel; version=1.1.0, \
 org.osgi.service.url; version=1.0.0, \
 org.osgi.util.tracker; version=1.5.1 \
 ${jre-${java.specification.version}}

The last line must be substituted for one of the definitions further down in the file that is suitable for the jvm you are using.

You will take these lines and copy them into the conf/config.properties file, after having replaced the line $\{jre-$\{java.specification.version}} with all of the lines relevant to your version of the jvm.

For example, for a 1.7 jvm, you will find this property definition:

jre-1.7=, \
 javax.accessibility;uses:="javax.swing.text";version="0.0.0.1_007_JavaSE", \
 javax.activation;version="0.0.0.1_007_JavaSE", \
 javax.activity;version="0.0.0.1_007_JavaSE", \
 javax.annotation.processing;uses:="javax.tools,javax.lang.model,javax.lang.model.element,javax.lang.model.util";version="0.0.0.1_007_JavaSE", \
 javax.annotation;version="0.0.0.1_007_JavaSE", \
 javax.crypto.interfaces;uses:="javax.crypto.spec,javax.crypto";version="0.0.0.1_007_JavaSE", \
 javax.crypto.spec;uses:="javax.crypto";version="0.0.0.1_007_JavaSE", \
 javax.crypto;uses:="javax.crypto.spec";version="0.0.0.1_007_JavaSE", \
 javax.imageio.event;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", \
 javax.imageio.metadata;uses:="org.w3c.dom,javax.imageio";version="0.0.0.1_007_JavaSE", \
 javax.imageio.plugins.bmp;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", \
 javax.imageio.plugins.jpeg;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", \
 javax.imageio.spi;uses:="javax.imageio.stream,javax.imageio,javax.imageio.metadata";version="0.0.0.1_007_JavaSE", \
 javax.imageio.stream;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", \
 javax.imageio;uses:="javax.imageio.metadata,javax.imageio.stream,javax.imageio.spi,javax.imageio.event";version="0.0.0.1_007_JavaSE", \
 javax.jws.soap;version="0.0.0.1_007_JavaSE", \
 javax.jws;version="0.0.0.1_007_JavaSE", \
 javax.lang.model.element;uses:="javax.lang.model.type,javax.lang.model";version="0.0.0.1_007_JavaSE", \
 javax.lang.model.type;uses:="javax.lang.model.element,javax.lang.model";version="0.0.0.1_007_JavaSE", \
 javax.lang.model.util;uses:="javax.lang.model,javax.lang.model.element,javax.annotation.processing,javax.lang.model.type";version="0.0.0.1_007_JavaSE", \
 javax.lang.model;version="0.0.0.1_007_JavaSE", \
 javax.management.loading;uses:="javax.management";version="0.0.0.1_007_JavaSE", \
 javax.management.modelmbean;uses:="javax.management,javax.management.loading";version="0.0.0.1_007_JavaSE", \
 javax.management.monitor;uses:="javax.management";version="0.0.0.1_007_JavaSE", \
 javax.management.openmbean;uses:="javax.management";version="0.0.0.1_007_JavaSE", \
 javax.management.relation;uses:="javax.management";version="0.0.0.1_007_JavaSE", \
 javax.management.remote.rmi;uses:="javax.management.remote,javax.security.auth,javax.management,javax.management.loading,javax.naming,javax.rmi.ssl,org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,javax.rmi.CORBA,javax.rmi";version="0.0.0.1_007_JavaSE", \
 javax.management.remote;uses:="javax.security.auth,javax.management";version="0.0.0.1_007_JavaSE", \
 javax.management.timer;uses:="javax.management";version="0.0.0.1_007_JavaSE", \
 javax.management;uses:="javax.management.loading,javax.management.openmbean";version="0.0.0.1_007_JavaSE", \
 javax.naming.directory;uses:="javax.naming";version="0.0.0.1_007_JavaSE", \
 javax.naming.event;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_007_JavaSE", \
 javax.naming.ldap;uses:="javax.naming,javax.naming.directory,javax.net.ssl,javax.naming.event";version="0.0.0.1_007_JavaSE", \
 javax.naming.spi;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_007_JavaSE", \
 javax.naming;uses:="javax.naming.spi";version="0.0.0.1_007_JavaSE", \
 javax.net.ssl;uses:="javax.security.cert,javax.security.auth.x500,javax.net";version="0.0.0.1_007_JavaSE", \
 javax.net;version="0.0.0.1_007_JavaSE", \
 javax.print.attribute.standard;uses:="javax.print.attribute";version="0.0.0.1_007_JavaSE", \
 javax.print.attribute;version="0.0.0.1_007_JavaSE", \
 javax.print.event;uses:="javax.print,javax.print.attribute";version="0.0.0.1_007_JavaSE", \
 javax.print;uses:="javax.print.attribute,javax.print.event,javax.print.attribute.standard";version="0.0.0.1_007_JavaSE", \
 javax.rmi.CORBA;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,org.omg.SendingContext";version="0.0.0.1_007_JavaSE", \
 javax.rmi.ssl;uses:="javax.net,javax.net.ssl";version="0.0.0.1_007_JavaSE", \
 javax.rmi;uses:="org.omg.CORBA,javax.rmi.CORBA";version="0.0.0.1_007_JavaSE", \
 javax.script;version="0.0.0.1_007_JavaSE", \
 javax.security.auth.callback;version="0.0.0.1_007_JavaSE", \
 javax.security.auth.kerberos;uses:="javax.security.auth,javax.crypto";version="0.0.0.1_007_JavaSE", \
 javax.security.auth.login;uses:="javax.security.auth,javax.security.auth.callback";version="0.0.0.1_007_JavaSE", \
 javax.security.auth.spi;uses:="javax.security.auth.callback,javax.security.auth.login,javax.security.auth";version="0.0.0.1_007_JavaSE", \
 javax.security.auth.x500;uses:="javax.security.auth";version="0.0.0.1_007_JavaSE", \
 javax.security.auth;version="0.0.0.1_007_JavaSE", \
 javax.security.cert;version="0.0.0.1_007_JavaSE", \
 javax.security.sasl;uses:="javax.security.auth.callback";version="0.0.0.1_007_JavaSE", \
 javax.sound.midi.spi;uses:="javax.sound.midi";version="0.0.0.1_007_JavaSE", \
 javax.sound.midi;uses:="javax.sound.midi.spi";version="0.0.0.1_007_JavaSE", \
 javax.sound.sampled.spi;uses:="javax.sound.sampled";version="0.0.0.1_007_JavaSE", \
 javax.sound.sampled;uses:="javax.sound.sampled.spi";version="0.0.0.1_007_JavaSE", \
 javax.sql.rowset.serial;uses:="javax.sql.rowset";version="0.0.0.1_007_JavaSE", \
 javax.sql.rowset.spi;uses:="javax.sql,javax.naming,javax.sql.rowset";version="0.0.0.1_007_JavaSE", \
 javax.sql.rowset;uses:="javax.sql,javax.sql.rowset.serial,javax.sql.rowset.spi";version="0.0.0.1_007_JavaSE", \
 javax.sql;uses:="javax.transaction.xa";version="0.0.0.1_007_JavaSE", \
 javax.swing.border;uses:="javax.swing";version="0.0.0.1_007_JavaSE", \
 javax.swing.colorchooser;uses:="javax.swing,javax.swing.border,javax.swing.event,javax.swing.text";version="0.0.0.1_007_JavaSE", \
 javax.swing.event;uses:="javax.swing,javax.swing.text,javax.swing.table,javax.swing.tree,javax.swing.undo";version="0.0.0.1_007_JavaSE", \
 javax.swing.filechooser;uses:="javax.swing";version="0.0.0.1_007_JavaSE", \
 javax.swing.plaf.basic;uses:="javax.swing.border,javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.event,javax.swing.colorchooser,javax.accessibility,javax.swing.filechooser,javax.swing.text.html,javax.sound.sampled,javax.swing.table,javax.swing.plaf.synth,javax.swing.tree";version="0.0.0.1_007_JavaSE", \
 javax.swing.plaf.metal;uses:="javax.swing.plaf,javax.swing,javax.swing.border,javax.swing.text,javax.swing.plaf.basic,javax.swing.filechooser,javax.swing.event,javax.swing.tree";version="0.0.0.1_007_JavaSE", \
 javax.swing.plaf.multi;uses:="javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_007_JavaSE", \
 javax.swing.plaf.nimbus;uses:="javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.plaf.synth";version="0.0.0.1_007_JavaSE", \
 javax.swing.plaf.synth;uses:="javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.border,javax.swing.plaf.basic,javax.swing.colorchooser,javax.swing.event,javax.xml.parsers,org.xml.sax,org.xml.sax.helpers,javax.swing.table,javax.swing.tree";version="0.0.0.1_007_JavaSE", \
 javax.swing.plaf;uses:="javax.swing,javax.swing.border,javax.accessibility,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_007_JavaSE", \
 javax.swing.table;uses:="javax.swing.event,javax.swing.plaf,javax.swing.border,javax.swing,javax.accessibility";version="0.0.0.1_007_JavaSE", \
 javax.swing.text.html.parser;uses:="javax.swing.text,javax.swing.text.html";version="0.0.0.1_007_JavaSE", \
 javax.swing.text.html;uses:="javax.swing.event,javax.swing.text,javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.undo";version="0.0.0.1_007_JavaSE", \
 javax.swing.text.rtf;uses:="javax.swing.text";version="0.0.0.1_007_JavaSE", \
 javax.swing.text;uses:="javax.swing.event,javax.swing.tree,javax.swing.undo,javax.swing,javax.swing.plaf,javax.swing.plaf.basic,javax.print,javax.print.attribute,javax.accessibility,javax.swing.text.html";version="0.0.0.1_007_JavaSE", \
 javax.swing.tree;uses:="javax.swing.event,javax.swing,javax.swing.border,javax.swing.plaf,javax.swing.plaf.basic";version="0.0.0.1_007_JavaSE", \
 javax.swing.undo;uses:="javax.swing,javax.swing.event";version="0.0.0.1_007_JavaSE", \
 javax.swing;uses:="javax.swing.event,javax.accessibility,javax.swing.text,javax.swing.plaf,javax.swing.border,javax.swing.tree,javax.swing.table,javax.swing.colorchooser,javax.swing.plaf.basic,javax.swing.text.html,javax.swing.filechooser,javax.print,javax.print.attribute,javax.swing.plaf.metal";version="0.0.0.1_007_JavaSE", \
 javax.tools;uses:="javax.lang.model.element,javax.annotation.processing,javax.lang.model";version="0.0.0.1_007_JavaSE", \
 javax.transaction.xa;version="0.0.0.1_007_JavaSE", \
 javax.transaction;version="0.0.0.1_007_JavaSE", \
 javax.xml.bind.annotation.adapters;uses:="javax.xml.bind";version="0.0.0.1_007_JavaSE", \
 javax.xml.bind.annotation;uses:="javax.xml.transform,javax.xml.bind,javax.xml.parsers,javax.xml.transform.dom,org.w3c.dom";version="0.0.0.1_007_JavaSE", \
 javax.xml.bind.attachment;uses:="javax.activation";version="0.0.0.1_007_JavaSE", \
 javax.xml.bind.helpers;uses:="javax.xml.bind.annotation.adapters,javax.xml.transform.dom,org.w3c.dom,org.xml.sax,javax.xml.bind.attachment,javax.xml.stream,javax.xml.transform,javax.xml.transform.stream,javax.xml.validation,javax.xml.transform.sax,javax.xml.bind,javax.xml.parsers";version="0.0.0.1_007_JavaSE", \
 javax.xml.bind.util;uses:="javax.xml.transform.sax,javax.xml.bind,org.xml.sax,org.xml.sax.ext,org.xml.sax.helpers";version="0.0.0.1_007_JavaSE", \
 javax.xml.bind;uses:="javax.xml.validation,javax.xml.namespace,javax.xml.datatype,javax.xml.transform,javax.xml.bind.annotation,javax.xml.transform.stream,org.w3c.dom,javax.xml.bind.attachment,javax.xml.stream,javax.xml.bind.annotation.adapters,org.xml.sax";version="0.0.0.1_007_JavaSE", \
 javax.xml.crypto.dom;uses:="javax.xml.crypto,org.w3c.dom";version="0.0.0.1_007_JavaSE", \
 javax.xml.crypto.dsig.dom;uses:="javax.xml.crypto.dsig,javax.xml.crypto,org.w3c.dom,javax.xml.crypto.dom";version="0.0.0.1_007_JavaSE", \
 javax.xml.crypto.dsig.keyinfo;uses:="javax.xml.crypto";version="0.0.0.1_007_JavaSE", \
 javax.xml.crypto.dsig.spec;uses:="javax.xml.crypto";version="0.0.0.1_007_JavaSE", \
 javax.xml.crypto.dsig;uses:="javax.xml.crypto,javax.xml.crypto.dsig.spec,javax.xml.crypto.dsig.keyinfo";version="0.0.0.1_007_JavaSE", \
 javax.xml.crypto;uses:="javax.xml.crypto.dsig.keyinfo";version="0.0.0.1_007_JavaSE", \
 javax.xml.datatype;uses:="javax.xml.namespace";version="0.0.0.1_007_JavaSE", \
 javax.xml.namespace;version="0.0.0.1_007_JavaSE", \
 javax.xml.parsers;uses:="javax.xml.validation,org.w3c.dom,org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_007_JavaSE", \
 javax.xml.soap;uses:="javax.activation,javax.xml.namespace,org.w3c.dom,javax.xml.transform.dom,javax.xml.transform";version="0.0.0.1_007_JavaSE", \
 javax.xml.stream.events;uses:="javax.xml.namespace,javax.xml.stream";version="0.0.0.1_007_JavaSE", \
 javax.xml.stream.util;uses:="javax.xml.stream,javax.xml.stream.events,javax.xml.namespace";version="0.0.0.1_007_JavaSE", \
 javax.xml.stream;uses:="javax.xml.stream.events,javax.xml.namespace,javax.xml.stream.util,javax.xml.transform";version="0.0.0.1_007_JavaSE", \
 javax.xml.transform.dom;uses:="javax.xml.transform,org.w3c.dom";version="0.0.0.1_007_JavaSE", \
 javax.xml.transform.sax;uses:="org.xml.sax.ext,javax.xml.transform,org.xml.sax,javax.xml.transform.stream";version="0.0.0.1_007_JavaSE", \
 javax.xml.transform.stax;uses:="javax.xml.stream,javax.xml.transform,javax.xml.stream.events";version="0.0.0.1_007_JavaSE", \
 javax.xml.transform.stream;uses:="javax.xml.transform";version="0.0.0.1_007_JavaSE", \
 javax.xml.transform;version="0.0.0.1_007_JavaSE", \
 javax.xml.validation;uses:="org.w3c.dom.ls,javax.xml.transform,javax.xml.transform.stream,org.xml.sax,org.w3c.dom";version="0.0.0.1_007_JavaSE", \
 javax.xml.ws.handler.soap;uses:="javax.xml.ws.handler,javax.xml.namespace,javax.xml.soap,javax.xml.bind";version="0.0.0.1_007_JavaSE", \
 javax.xml.ws.handler;uses:="javax.xml.ws,javax.xml.namespace";version="0.0.0.1_007_JavaSE", \
 javax.xml.ws.http;uses:="javax.xml.ws";version="0.0.0.1_007_JavaSE", \
 javax.xml.ws.soap;uses:="javax.xml.ws.spi,javax.xml.ws,javax.xml.soap";version="0.0.0.1_007_JavaSE", \
 javax.xml.ws.spi.http;version="0.0.0.1_007_JavaSE", \
 javax.xml.ws.spi;uses:="javax.xml.ws,javax.xml.ws.wsaddressing,javax.xml.transform,org.w3c.dom,javax.xml.namespace,javax.xml.ws.handler,javax.xml.bind";version="0.0.0.1_007_JavaSE", \
 javax.xml.ws.wsaddressing;uses:="javax.xml.bind.annotation,javax.xml.namespace,org.w3c.dom,javax.xml.transform,javax.xml.bind,javax.xml.ws,javax.xml.ws.spi";version="0.0.0.1_007_JavaSE", \
 javax.xml.ws;uses:="javax.xml.ws.handler,javax.xml.ws.spi,javax.xml.ws.spi.http,javax.xml.transform,org.w3c.dom,javax.xml.bind.annotation,javax.xml.transform.stream,javax.xml.bind,javax.xml.namespace";version="0.0.0.1_007_JavaSE", \
 javax.xml.xpath;uses:="org.xml.sax,javax.xml.namespace";version="0.0.0.1_007_JavaSE", \
 javax.xml;version="0.0.0.1_007_JavaSE", \
 org.ietf.jgss;version="0.0.0.1_007_JavaSE", \
 org.omg.CORBA.DynAnyPackage;uses:="org.omg.CORBA";version="0.0.0.1_007_JavaSE", \
 org.omg.CORBA.ORBPackage;uses:="org.omg.CORBA";version="0.0.0.1_007_JavaSE", \
 org.omg.CORBA.TypeCodePackage;uses:="org.omg.CORBA";version="0.0.0.1_007_JavaSE", \
 org.omg.CORBA.portable;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.CORBA;uses:="org.omg.CORBA.portable,org.omg.CORBA.DynAnyPackage,org.omg.CORBA.ORBPackage,org.omg.CORBA_2_3.portable,org.omg.CORBA.TypeCodePackage";version="0.0.0.1_007_JavaSE", \
 org.omg.CORBA_2_3.portable;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.CORBA_2_3;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.CosNaming.NamingContextExtPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.CosNaming.NamingContextPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.CosNaming";version="0.0.0.1_007_JavaSE", \
 org.omg.CosNaming;uses:="org.omg.CORBA.portable,org.omg.CORBA,org.omg.PortableServer,org.omg.CosNaming.NamingContextPackage,org.omg.CosNaming.NamingContextExtPackage";version="0.0.0.1_007_JavaSE", \
 org.omg.Dynamic;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.DynamicAny.DynAnyFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.DynamicAny.DynAnyPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.DynamicAny;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.DynamicAny.DynAnyFactoryPackage,org.omg.DynamicAny.DynAnyPackage";version="0.0.0.1_007_JavaSE", \
 org.omg.IOP.CodecFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.IOP.CodecPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.IOP;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP.CodecFactoryPackage,org.omg.IOP.CodecPackage";version="0.0.0.1_007_JavaSE", \
 org.omg.Messaging;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.PortableInterceptor.ORBInitInfoPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.PortableInterceptor;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP,org.omg.PortableInterceptor.ORBInitInfoPackage,org.omg.CORBA_2_3.portable,org.omg.Dynamic";version="0.0.0.1_007_JavaSE", \
 org.omg.PortableServer.CurrentPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.PortableServer.POAManagerPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.PortableServer.POAPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.PortableServer.ServantLocatorPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.PortableServer.portable;uses:="org.omg.CORBA,org.omg.PortableServer";version="0.0.0.1_007_JavaSE", \
 org.omg.PortableServer;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.PortableServer.CurrentPackage,org.omg.PortableServer.POAManagerPackage,org.omg.PortableServer.POAPackage,org.omg.PortableServer.portable,org.omg.CORBA_2_3,org.omg.PortableServer.ServantLocatorPackage";version="0.0.0.1_007_JavaSE", \
 org.omg.SendingContext;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \
 org.omg.stub.java.rmi;uses:="javax.rmi.CORBA";version="0.0.0.1_007_JavaSE", \
 org.w3c.dom.bootstrap;uses:="org.w3c.dom";version="0.0.0.1_007_JavaSE", \
 org.w3c.dom.events;uses:="org.w3c.dom,org.w3c.dom.views";version="0.0.0.1_007_JavaSE", \
 org.w3c.dom.ls;uses:="org.w3c.dom,org.w3c.dom.events,org.w3c.dom.traversal";version="0.0.0.1_007_JavaSE", \
 org.w3c.dom;version="0.0.0.1_007_JavaSE", \
 org.xml.sax.ext;uses:="org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_007_JavaSE", \
 org.xml.sax.helpers;uses:="org.xml.sax";version="0.0.0.1_007_JavaSE", \
 org.xml.sax;version="0.0.0.1_007_JavaSE"

Remove the definition for the javax.transaction packages, and remove the uses:= clause for the javax.sql packages (but leaving the version clause). Concatenate all the lines together. You’ll wind up with something like this in your conf/config.properties file:

org.osgi.framework.system.packages=org.osgi.framework;version=1.7.0, org.osgi.framework.hooks.bundle;version=1.1.0, org.osgi.framework.hooks.resolver;version=1.0.0, org.osgi.framework.hooks.service;version=1.1.0, org.osgi.framework.hooks.weaving;version=1.0.0, org.osgi.framework.launch;version=1.1.0, org.osgi.framework.namespace;version=1.0.0, org.osgi.framework.startlevel;version=1.0.0, org.osgi.framework.wiring;version=1.1.0, org.osgi.resource;version=1.0.0, org.osgi.service.packageadmin; version=1.2.0, org.osgi.service.startlevel; version=1.1.0, org.osgi.service.url;version=1.0.0, org.osgi.util.tracker;version=1.5.1 javax.accessibility;uses:="javax.swing.text";version="0.0.0.1_007_JavaSE", javax.activation;version="0.0.0.1_007_JavaSE", javax.activity;version="0.0.0.1_007_JavaSE", javax.annotation.processing;uses:="javax.tools,javax.lang.model,javax.lang.model.element,javax.lang.model.util";version="0.0.0.1_007_JavaSE", javax.annotation;version="0.0.0.1_007_JavaSE", javax.crypto.interfaces;uses:="javax.crypto.spec,javax.crypto";version="0.0.0.1_007_JavaSE", javax.crypto.spec;uses:="javax.crypto";version="0.0.0.1_007_JavaSE", javax.crypto;uses:="javax.crypto.spec";version="0.0.0.1_007_JavaSE", javax.imageio.event;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", javax.imageio.metadata;uses:="org.w3c.dom,javax.imageio";version="0.0.0.1_007_JavaSE", javax.imageio.plugins.bmp;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", javax.imageio.plugins.jpeg;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", javax.imageio.spi;uses:="javax.imageio.stream,javax.imageio,javax.imageio.metadata";version="0.0.0.1_007_JavaSE", javax.imageio.stream;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", javax.imageio;uses:="javax.imageio.metadata,javax.imageio.stream,javax.imageio.spi,javax.imageio.event";version="0.0.0.1_007_JavaSE", javax.jws.soap;version="0.0.0.1_007_JavaSE", javax.jws;version="0.0.0.1_007_JavaSE", javax.lang.model.element;uses:="javax.lang.model.type,javax.lang.model";version="0.0.0.1_007_JavaSE", javax.lang.model.type;uses:="javax.lang.model.element,javax.lang.model";version="0.0.0.1_007_JavaSE", javax.lang.model.util;uses:="javax.lang.model,javax.lang.model.element,javax.annotation.processing,javax.lang.model.type";version="0.0.0.1_007_JavaSE", javax.lang.model;version="0.0.0.1_007_JavaSE", javax.management.loading;uses:="javax.management";version="0.0.0.1_007_JavaSE", javax.management.modelmbean;uses:="javax.management,javax.management.loading";version="0.0.0.1_007_JavaSE", javax.management.monitor;uses:="javax.management";version="0.0.0.1_007_JavaSE", javax.management.openmbean;uses:="javax.management";version="0.0.0.1_007_JavaSE", javax.management.relation;uses:="javax.management";version="0.0.0.1_007_JavaSE", javax.management.remote.rmi;uses:="javax.management.remote,javax.security.auth,javax.management,javax.management.loading,javax.naming,javax.rmi.ssl,org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,javax.rmi.CORBA,javax.rmi";version="0.0.0.1_007_JavaSE", javax.management.remote;uses:="javax.security.auth,javax.management";version="0.0.0.1_007_JavaSE", javax.management.timer;uses:="javax.management";version="0.0.0.1_007_JavaSE", javax.management;uses:="javax.management.loading,javax.management.openmbean";version="0.0.0.1_007_JavaSE", javax.naming.directory;uses:="javax.naming";version="0.0.0.1_007_JavaSE", javax.naming.event;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_007_JavaSE", javax.naming.ldap;uses:="javax.naming,javax.naming.directory,javax.net.ssl,javax.naming.event";version="0.0.0.1_007_JavaSE", javax.naming.spi;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_007_JavaSE", javax.naming;uses:="javax.naming.spi";version="0.0.0.1_007_JavaSE", javax.net.ssl;uses:="javax.security.cert,javax.security.auth.x500,javax.net";version="0.0.0.1_007_JavaSE", javax.net;version="0.0.0.1_007_JavaSE", javax.print.attribute.standard;uses:="javax.print.attribute";version="0.0.0.1_007_JavaSE", javax.print.attribute;version="0.0.0.1_007_JavaSE", javax.print.event;uses:="javax.print,javax.print.attribute";version="0.0.0.1_007_JavaSE", javax.print;uses:="javax.print.attribute,javax.print.event,javax.print.attribute.standard";version="0.0.0.1_007_JavaSE", javax.rmi.CORBA;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,org.omg.SendingContext";version="0.0.0.1_007_JavaSE", javax.rmi.ssl;uses:="javax.net,javax.net.ssl";version="0.0.0.1_007_JavaSE", javax.rmi;uses:="org.omg.CORBA,javax.rmi.CORBA";version="0.0.0.1_007_JavaSE", javax.script;version="0.0.0.1_007_JavaSE", javax.security.auth.callback;version="0.0.0.1_007_JavaSE", javax.security.auth.kerberos;uses:="javax.security.auth,javax.crypto";version="0.0.0.1_007_JavaSE", javax.security.auth.login;uses:="javax.security.auth,javax.security.auth.callback";version="0.0.0.1_007_JavaSE", javax.security.auth.spi;uses:="javax.security.auth.callback,javax.security.auth.login,javax.security.auth";version="0.0.0.1_007_JavaSE", javax.security.auth.x500;uses:="javax.security.auth";version="0.0.0.1_007_JavaSE", javax.security.auth;version="0.0.0.1_007_JavaSE", javax.security.cert;version="0.0.0.1_007_JavaSE", javax.security.sasl;uses:="javax.security.auth.callback";version="0.0.0.1_007_JavaSE", javax.sound.midi.spi;uses:="javax.sound.midi";version="0.0.0.1_007_JavaSE", javax.sound.midi;uses:="javax.sound.midi.spi";version="0.0.0.1_007_JavaSE", javax.sound.sampled.spi;uses:="javax.sound.sampled";version="0.0.0.1_007_JavaSE", javax.sound.sampled;uses:="javax.sound.sampled.spi";version="0.0.0.1_007_JavaSE", javax.sql.rowset.serial;version="0.0.0.1_007_JavaSE", javax.sql.rowset.spi;version="0.0.0.1_007_JavaSE", javax.sql.rowset;version="0.0.0.1_007_JavaSE", javax.sql;version="0.0.0.1_007_JavaSE", javax.swing.border;uses:="javax.swing";version="0.0.0.1_007_JavaSE", javax.swing.colorchooser;uses:="javax.swing,javax.swing.border,javax.swing.event,javax.swing.text";version="0.0.0.1_007_JavaSE", javax.swing.event;uses:="javax.swing,javax.swing.text,javax.swing.table,javax.swing.tree,javax.swing.undo";version="0.0.0.1_007_JavaSE", javax.swing.filechooser;uses:="javax.swing";version="0.0.0.1_007_JavaSE", javax.swing.plaf.basic;uses:="javax.swing.border,javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.event,javax.swing.colorchooser,javax.accessibility,javax.swing.filechooser,javax.swing.text.html,javax.sound.sampled,javax.swing.table,javax.swing.plaf.synth,javax.swing.tree";version="0.0.0.1_007_JavaSE", javax.swing.plaf.metal;uses:="javax.swing.plaf,javax.swing,javax.swing.border,javax.swing.text,javax.swing.plaf.basic,javax.swing.filechooser,javax.swing.event,javax.swing.tree";version="0.0.0.1_007_JavaSE", javax.swing.plaf.multi;uses:="javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_007_JavaSE", javax.swing.plaf.nimbus;uses:="javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.plaf.synth";version="0.0.0.1_007_JavaSE", javax.swing.plaf.synth;uses:="javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.border,javax.swing.plaf.basic,javax.swing.colorchooser,javax.swing.event,javax.xml.parsers,org.xml.sax,org.xml.sax.helpers,javax.swing.table,javax.swing.tree";version="0.0.0.1_007_JavaSE", javax.swing.plaf;uses:="javax.swing,javax.swing.border,javax.accessibility,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_007_JavaSE", javax.swing.table;uses:="javax.swing.event,javax.swing.plaf,javax.swing.border,javax.swing,javax.accessibility";version="0.0.0.1_007_JavaSE", javax.swing.text.html.parser;uses:="javax.swing.text,javax.swing.text.html";version="0.0.0.1_007_JavaSE", javax.swing.text.html;uses:="javax.swing.event,javax.swing.text,javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.undo";version="0.0.0.1_007_JavaSE", javax.swing.text.rtf;uses:="javax.swing.text";version="0.0.0.1_007_JavaSE", javax.swing.text;uses:="javax.swing.event,javax.swing.tree,javax.swing.undo,javax.swing,javax.swing.plaf,javax.swing.plaf.basic,javax.print,javax.print.attribute,javax.accessibility,javax.swing.text.html";version="0.0.0.1_007_JavaSE", javax.swing.tree;uses:="javax.swing.event,javax.swing,javax.swing.border,javax.swing.plaf,javax.swing.plaf.basic";version="0.0.0.1_007_JavaSE", javax.swing.undo;uses:="javax.swing,javax.swing.event";version="0.0.0.1_007_JavaSE", javax.swing;uses:="javax.swing.event,javax.accessibility,javax.swing.text,javax.swing.plaf,javax.swing.border,javax.swing.tree,javax.swing.table,javax.swing.colorchooser,javax.swing.plaf.basic,javax.swing.text.html,javax.swing.filechooser,javax.print,javax.print.attribute,javax.swing.plaf.metal";version="0.0.0.1_007_JavaSE", javax.tools;uses:="javax.lang.model.element,javax.annotation.processing,javax.lang.model";version="0.0.0.1_007_JavaSE", javax.xml.bind.annotation.adapters;uses:="javax.xml.bind";version="0.0.0.1_007_JavaSE", javax.xml.bind.annotation;uses:="javax.xml.transform,javax.xml.bind,javax.xml.parsers,javax.xml.transform.dom,org.w3c.dom";version="0.0.0.1_007_JavaSE", javax.xml.bind.attachment;uses:="javax.activation";version="0.0.0.1_007_JavaSE", javax.xml.bind.helpers;uses:="javax.xml.bind.annotation.adapters,javax.xml.transform.dom,org.w3c.dom,org.xml.sax,javax.xml.bind.attachment,javax.xml.stream,javax.xml.transform,javax.xml.transform.stream,javax.xml.validation,javax.xml.transform.sax,javax.xml.bind,javax.xml.parsers";version="0.0.0.1_007_JavaSE", javax.xml.bind.util;uses:="javax.xml.transform.sax,javax.xml.bind,org.xml.sax,org.xml.sax.ext,org.xml.sax.helpers";version="0.0.0.1_007_JavaSE", javax.xml.bind;uses:="javax.xml.validation,javax.xml.namespace,javax.xml.datatype,javax.xml.transform,javax.xml.bind.annotation,javax.xml.transform.stream,org.w3c.dom,javax.xml.bind.attachment,javax.xml.stream,javax.xml.bind.annotation.adapters,org.xml.sax";version="0.0.0.1_007_JavaSE", javax.xml.crypto.dom;uses:="javax.xml.crypto,org.w3c.dom";version="0.0.0.1_007_JavaSE", javax.xml.crypto.dsig.dom;uses:="javax.xml.crypto.dsig,javax.xml.crypto,org.w3c.dom,javax.xml.crypto.dom";version="0.0.0.1_007_JavaSE", javax.xml.crypto.dsig.keyinfo;uses:="javax.xml.crypto";version="0.0.0.1_007_JavaSE", javax.xml.crypto.dsig.spec;uses:="javax.xml.crypto";version="0.0.0.1_007_JavaSE", javax.xml.crypto.dsig;uses:="javax.xml.crypto,javax.xml.crypto.dsig.spec,javax.xml.crypto.dsig.keyinfo";version="0.0.0.1_007_JavaSE", javax.xml.crypto;uses:="javax.xml.crypto.dsig.keyinfo";version="0.0.0.1_007_JavaSE", javax.xml.datatype;uses:="javax.xml.namespace";version="0.0.0.1_007_JavaSE", javax.xml.namespace;version="0.0.0.1_007_JavaSE", javax.xml.parsers;uses:="javax.xml.validation,org.w3c.dom,org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_007_JavaSE", javax.xml.soap;uses:="javax.activation,javax.xml.namespace,org.w3c.dom,javax.xml.transform.dom,javax.xml.transform";version="0.0.0.1_007_JavaSE", javax.xml.stream.events;uses:="javax.xml.namespace,javax.xml.stream";version="0.0.0.1_007_JavaSE", javax.xml.stream.util;uses:="javax.xml.stream,javax.xml.stream.events,javax.xml.namespace";version="0.0.0.1_007_JavaSE", javax.xml.stream;uses:="javax.xml.stream.events,javax.xml.namespace,javax.xml.stream.util,javax.xml.transform";version="0.0.0.1_007_JavaSE", javax.xml.transform.dom;uses:="javax.xml.transform,org.w3c.dom";version="0.0.0.1_007_JavaSE", javax.xml.transform.sax;uses:="org.xml.sax.ext,javax.xml.transform,org.xml.sax,javax.xml.transform.stream";version="0.0.0.1_007_JavaSE", javax.xml.transform.stax;uses:="javax.xml.stream,javax.xml.transform,javax.xml.stream.events";version="0.0.0.1_007_JavaSE", javax.xml.transform.stream;uses:="javax.xml.transform";version="0.0.0.1_007_JavaSE", javax.xml.transform;version="0.0.0.1_007_JavaSE", javax.xml.validation;uses:="org.w3c.dom.ls,javax.xml.transform,javax.xml.transform.stream,org.xml.sax,org.w3c.dom";version="0.0.0.1_007_JavaSE", javax.xml.ws.handler.soap;uses:="javax.xml.ws.handler,javax.xml.namespace,javax.xml.soap,javax.xml.bind";version="0.0.0.1_007_JavaSE", javax.xml.ws.handler;uses:="javax.xml.ws,javax.xml.namespace";version="0.0.0.1_007_JavaSE", javax.xml.ws.http;uses:="javax.xml.ws";version="0.0.0.1_007_JavaSE", javax.xml.ws.soap;uses:="javax.xml.ws.spi,javax.xml.ws,javax.xml.soap";version="0.0.0.1_007_JavaSE", javax.xml.ws.spi.http;version="0.0.0.1_007_JavaSE", javax.xml.ws.spi;uses:="javax.xml.ws,javax.xml.ws.wsaddressing,javax.xml.transform,org.w3c.dom,javax.xml.namespace,javax.xml.ws.handler,javax.xml.bind";version="0.0.0.1_007_JavaSE", javax.xml.ws.wsaddressing;uses:="javax.xml.bind.annotation,javax.xml.namespace,org.w3c.dom,javax.xml.transform,javax.xml.bind,javax.xml.ws,javax.xml.ws.spi";version="0.0.0.1_007_JavaSE", javax.xml.ws;uses:="javax.xml.ws.handler,javax.xml.ws.spi,javax.xml.ws.spi.http,javax.xml.transform,org.w3c.dom,javax.xml.bind.annotation,javax.xml.transform.stream,javax.xml.bind,javax.xml.namespace";version="0.0.0.1_007_JavaSE", javax.xml.xpath;uses:="org.xml.sax,javax.xml.namespace";version="0.0.0.1_007_JavaSE", javax.xml;version="0.0.0.1_007_JavaSE", org.ietf.jgss;version="0.0.0.1_007_JavaSE", org.omg.CORBA.DynAnyPackage;uses:="org.omg.CORBA";version="0.0.0.1_007_JavaSE", org.omg.CORBA.ORBPackage;uses:="org.omg.CORBA";version="0.0.0.1_007_JavaSE", org.omg.CORBA.TypeCodePackage;uses:="org.omg.CORBA";version="0.0.0.1_007_JavaSE", org.omg.CORBA.portable;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable";version="0.0.0.1_007_JavaSE", org.omg.CORBA;uses:="org.omg.CORBA.portable,org.omg.CORBA.DynAnyPackage,org.omg.CORBA.ORBPackage,org.omg.CORBA_2_3.portable,org.omg.CORBA.TypeCodePackage";version="0.0.0.1_007_JavaSE", org.omg.CORBA_2_3.portable;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.CORBA_2_3;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.CosNaming.NamingContextExtPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.CosNaming.NamingContextPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.CosNaming";version="0.0.0.1_007_JavaSE", org.omg.CosNaming;uses:="org.omg.CORBA.portable,org.omg.CORBA,org.omg.PortableServer,org.omg.CosNaming.NamingContextPackage,org.omg.CosNaming.NamingContextExtPackage";version="0.0.0.1_007_JavaSE", org.omg.Dynamic;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.DynamicAny.DynAnyFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.DynamicAny.DynAnyPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.DynamicAny;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.DynamicAny.DynAnyFactoryPackage,org.omg.DynamicAny.DynAnyPackage";version="0.0.0.1_007_JavaSE", org.omg.IOP.CodecFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.IOP.CodecPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.IOP;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP.CodecFactoryPackage,org.omg.IOP.CodecPackage";version="0.0.0.1_007_JavaSE", org.omg.Messaging;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.PortableInterceptor.ORBInitInfoPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.PortableInterceptor;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP,org.omg.PortableInterceptor.ORBInitInfoPackage,org.omg.CORBA_2_3.portable,org.omg.Dynamic";version="0.0.0.1_007_JavaSE", org.omg.PortableServer.CurrentPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.PortableServer.POAManagerPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.PortableServer.POAPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.PortableServer.ServantLocatorPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.PortableServer.portable;uses:="org.omg.CORBA,org.omg.PortableServer";version="0.0.0.1_007_JavaSE", org.omg.PortableServer;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.PortableServer.CurrentPackage,org.omg.PortableServer.POAManagerPackage,org.omg.PortableServer.POAPackage,org.omg.PortableServer.portable,org.omg.CORBA_2_3,org.omg.PortableServer.ServantLocatorPackage";version="0.0.0.1_007_JavaSE", org.omg.SendingContext;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", org.omg.stub.java.rmi;uses:="javax.rmi.CORBA";version="0.0.0.1_007_JavaSE", org.w3c.dom.bootstrap;uses:="org.w3c.dom";version="0.0.0.1_007_JavaSE", org.w3c.dom.events;uses:="org.w3c.dom,org.w3c.dom.views";version="0.0.0.1_007_JavaSE", org.w3c.dom.ls;uses:="org.w3c.dom,org.w3c.dom.events,org.w3c.dom.traversal";version="0.0.0.1_007_JavaSE", org.w3c.dom;version="0.0.0.1_007_JavaSE", org.xml.sax.ext;uses:="org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_007_JavaSE", org.xml.sax.helpers;uses:="org.xml.sax";version="0.0.0.1_007_JavaSE", org.xml.sax;version="0.0.0.1_007_JavaSE"

You should now be able to start Felix, and deploy all the jars listed on this page. You should see output similar to this on the console, using the felix:lb command:

    ID|State      |Level|Name
    0|Active     |    0|System Bundle (4.4.1)
    1|Active     |    1|ASM (7.0)
    2|Active     |    1|ASM commons classes (7.0)
    3|Active     |    1|ASM Tree class visitor (7.0)
    4|Active     |    1|geronimo-jta_1.1_spec (1.1.1)
    5|Active     |    1|javax.annotation API (1.2.0)
    6|Active     |    1|javax.mail bundle from Glassfish (1.4.1.v201005082020)
    7|Active     |    1|Java Server Pages Standard Tag Library API Bundle (1.2.0.v201105211821)
    8|Active     |    1|JavaServer Pages (TM) TagLib Implementation (1.2.2)
    9|Active     |    1|Jetty :: Servlet Annotations ({VERSION})
   10|Active     |    1|Jetty :: Deployers ({VERSION})
   11|Active     |    1|Jetty :: Http Utility ({VERSION})
   12|Active     |    1|Jetty :: IO Utility ({VERSION})
   13|Active     |    1|Jetty :: JNDI Naming ({VERSION})
   14|Active     |    1|Jetty :: OSGi :: Boot ({VERSION})
   15|Resolved   |    1|Jetty-OSGi-Jasper Integration ({VERSION})
   16|Active     |    1|Jetty Servlet API and Schemas for OSGi (3.1.0)
   17|Active     |    1|Jetty :: Plus ({VERSION})
   18|Active     |    1|Jetty :: Security ({VERSION})
   19|Active     |    1|Jetty :: Server Core ({VERSION})
   20|Active     |    1|Jetty :: Servlet Handling ({VERSION})
   21|Active     |    1|Jetty :: Utility Servlets and Filters ({VERSION})
   22|Active     |    1|Jetty :: Utilities ({VERSION})
   23|Active     |    1|Jetty :: Webapp Application Support ({VERSION})
   24|Active     |    1|Jetty :: XML utilities ({VERSION})
   25|Active     |    1|Apache Aries SPI Fly Dynamic Weaving Bundle (1.2)
   27|Active     |    1|Apache Felix Bundle Repository (2.0.2)
   28|Active     |    1|Apache Felix Configuration Admin Service (1.8.0)
   29|Active     |    1|Apache Felix EventAdmin (1.3.2)
   30|Active     |    1|Apache Felix Gogo Command (0.14.0)
   31|Active     |    1|Apache Felix Gogo Runtime (0.12.1)
   32|Active     |    1|Apache Felix Gogo Shell (0.10.0)
   33|Active     |    1|Apache Felix Log Service (1.0.1)
   34|Active     |    1|Jetty :: Apache JSP ({VERSION})
   35|Active     |    1|Eclipse Compiler for Java(TM) (3.8.2.v20130121-145325)
   36|Active     |    1|Mortbay EL API and Implementation (8.5.33.1)
   37|Active     |    1|Mortbay Jasper (8.5.33.1)
Eclipse

The Jetty OSGi integration has been successfully tested against Equinox Mars RC1.

Ensure that these services are present:

Eclipse Update Site

There is a list of Eclipse P2 sites for the jetty releases maintained at http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/

Each P2 repo has one big feature group that defines most of the Jetty jars. Beware: No 3rd party dependency jars are included, so you will need to have installed the dependencies listed previously in this document.

In addition, as the feature group includes websocket, you will need to download and have installed the jakarta.websocket-api jar:

Table 12. Extra Jars Required for Websocket
Jar Bundle Symbolic Name Location

jakarta.websocket-api

jakarta.websocket-api

Maven central

Metro

Metro is the reference implementation for web services. You can easily use Metro with Jetty to integrate web services with your web applications.

Metro Setup

  1. Download the Metro distribution and unpack it to your disk. We’ll refer to the unpacked location as $metro.home.

  2. Create the directory $jetty.home/lib/metro

  3. Copy the jars from $metro.home/lib to $jetty.home/lib/metro

  4. Edit the start.ini file and add an OPTION line for metro near the end.

    OPTIONS=metro

That’s all the setup you need to do to integrate Jetty and Metro.

Now read the Metro documentation on how to create web services. The Metro distribution you downloaded should also contain several example web applications in the $metro.home/samples directory that you can build and deploy to Jetty (simply by copying the war file produced by the build).

Here’s an example of the log output from Jetty when one of the sample Metro wars (from $metro.home/samples/async) is deployed to Jetty:

[2093] java -jar start.jar

2013-07-26 15:47:53.480:INFO:oejs.Server:main: jetty-9.0.4.v20130625
2013-07-26 15:47:53.549:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/home/user/jetty-home-12.0.9-SNAPSHOT/webapps/] at interval 1
Jul 26, 2013 3:47:53 PM com.sun.xml.ws.transport.http.servlet.WSServletContextListener contextInitialized
INFO: WSSERVLET12: JAX-WS context listener initializing
Jul 26, 2013 3:47:56 PM com.sun.xml.ws.server.MonitorBase createRoot
INFO: Metro monitoring rootname successfully set to: com.sun.metro:pp=/,type=WSEndpoint,name=/metro-async-AddNumbersService-AddNumbersImplPort
Jul 26, 2013 3:47:56 PM com.sun.xml.ws.transport.http.servlet.WSServletDelegate <init>
INFO: WSSERVLET14: JAX-WS servlet initializing
2013-07-26 15:47:56.800:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@75707c77{/metro-async,file:/tmp/jetty-0.0.0.0-8080-metro-async.war-_metro-async-any-/webapp/,AVAILABLE}{/metro-async.war}
2013-07-26 15:47:56.853:INFO:oejs.ServerConnector:main: Started ServerConnector@47dce809{HTTP/1.1}{0.0.0.0:8080}

Introducing Jetty

What is Jetty?

Eclipse Jetty is an open-source project providing an HTTP server, HTTP client, and Servlet container.

The Jetty documentation is broken up in to four parts:

  • The Getting Started Guide emphasizes beginning to use Jetty. It provides information about what Jetty is and where you can download it, and where to find Jetty in repositories like Central Maven. It also provides a Quick Start guide on how to get Jetty up and running as well as an overview of how and what to configure in Jetty.

  • The Operations Guide details configuring Jetty as a distributed package at a more granular level. From server startup to session management, logging, HTTP/2 support and Jetty optimization, these chapters will help administrators get the most out of their distributed Jetty server instances. This section also covers configuring many of the most common servlet container features such as JNDI and JMX.

  • Aimed at advanced users of Jetty, the Programming Guide focuses on Jetty development. A large portion of this section is focused on using Jetty as an embedded server in existing applications. It contains several examples and how-to guides for making the most out of the Jetty framework. This section also includes a guide on using the Jetty Maven plugin as well as information on debugging Jetty.

  • The Contribution Guide is aimed at those who want to contribute to the Jetty open source project. It includes instructions on interacting with the community, how to raise bugs, and how to report security issues. In addition, it also details source control and build information for the project.

What Version Do I Use?

Jetty 10 and 11 are the most recent versions of Jetty and has a great many improvements over previous versions. This documentation which focuses on Jetty 10. While many people continue to use older versions of Jetty, we generally recommend using Jetty 10 or 11 (more on the differences later) as they represent the version of Jetty that we will actively maintain and improve over the next few years.

It is important that only stable releases are used in production environments. Versions that have been deprecated or are released as Milestones (M) or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets.
Table 13. Jetty Versions
Version Year Home Min JVM Protocols Servlet JSP Status

11

2020-

Eclipse

11 (2)

HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI, JakartaEE Namespace(1)

5.0.0

3.0.0

Stable

10

2019-

Eclipse

11 (2)

HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI

4.0.1

2.2

Stable

9.4

2016-

Eclipse

1.8

HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI

3.1

2.3

Stable

9.3

2015-

Eclipse

1.8 (3)

HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI

3.1

2.3

Deprecated / End of Life December 2020

9.2

2014-2018

Eclipse

1.7 (3)

HTTP/1.1 RFC2616, javax.websocket, SPDY v3

3.1

2.3

Deprecated / End of Life January 2018

9.1

2013-2014

Eclipse

1.7 (3)

HTTP/1.1 RFC2616

3.1

2.3

Deprecated / End of Life May 2014

9.0

2013-2013

Eclipse

1.7 (3)

HTTP/1.1 RFC2616

3.1-beta

2.3

Deprecated / End of Life November 2013

8

2009-2014

Eclipse/Codehaus

1.6 (3)

HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3

3.0

2.2

Deprecated / End of Life November 2014

7

2008-2014

Eclipse/Codehaus

1.5

HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3

2.5

2.1

Deprecated / End of Life November 2014

6

2006-2010

Codehaus

1.4-1.5

HTTP/1.1 RFC2616

2.5

2.0

Deprecated / End of Life November 2010

5

2003-2009

Sourceforge

1.2-1.5

HTTP/1.1 RFC2616

2.4

2.0

Antique

4

2001-2006

Sourceforge

1.2, J2ME

HTTP/1.1 RFC2616

2.3

1.2

Ancient

3

1999-2002

Sourceforge

1.2

HTTP/1.1 RFC2068

2.2

1.1

Fossilized

2

1998-2000

Mortbay

1.1

HTTP/1.0 RFC1945

2.1

1.0

Legendary

1

1995-1998

Mortbay

1.0

HTTP/1.0 RFC1945

-

-

Mythical

  1. Due to Oracle’s ownership of the "Java" trademark, usage of the javax.* namespace has been restricted and the jakarta.* namespace was adopted by the Eclipse Foundation.

  2. JPMS module support is optional

  3. JDK9 and newer is not supported if using MultiRelease JAR Files, or Bytecode / Annotation scanning.

Jetty and Java EE Web Profile

Jetty implements aspects of the Java EE specification, primarily the Servlet Specification. Recent releases of the Java EE platform have introduced a Web Profile, recognizing that many developers need only a subset of the many technologies under the Java EE umbrella.

While Jetty itself does not ship all of the Web Profile technologies, Jetty architecture is such that you can plug in third party implementations to produce a container customized to your exact needs.

Java EE 7 Web Profile

In the forthcoming Java EE-7 specification, the Web Profile reflects updates in its component specifications and adds some new ones:

Table 14. JavaEE7 Web Profile
JSR Name Included with jetty-9.1.x Pluggable

JSR 340

Servlet Specification API 3.1

Yes

JSR 344

Java Server Faces 2.2 (JSF)

No

Yes, Mojarra or MyFaces

JSR 245 / JSR 341

Java Server Pages 2.3/Java Expression Language 3.0 (JSP/EL)

Yes

Yes

JSR 52

Java Standard Tag Library 1.2 (JSTL)

Yes

Yes

JSR 45

Debugging Support for Other Languages 1.0

Yes (via JSP)

Yes (via JSP)

JSR 346

Contexts and Dependency Injection for the JavaEE Platform 1.1 (Web Beans)

No

Yes, Weld

JSR 330

Dependency Injection for Java 1.0

No

Yes as part of a CDI implementation, Weld

JSR 316

Managed Beans 1.0

No

Yes, as part of another technology

JSR 345

Enterprise JavaBeans 3.2 Lite

No

JSR 338

Java Persistence 2.1 (JPA)

No

Yes, eg Hibernate

JSR 250

Common Annotations for the Java Platform 1.2

Yes

Partially (for non-core Servlet Spec annotations)

JSR 907

Java Transaction API 1.2 (JTA)

Yes

Yes

JSR 349

Bean Validation 1.1

No

Yes as part of another technology eg JSF, or a stand-alone implementation such as Hiberate Validator

JSR 339

Java API for RESTful Web Services 2.0 (JAX-RS)

No

JSR 356

Java API for Websocket 1.0

Yes

No

JSR 353

Java API for JSON Processing 1.0 (JSON-P)

No

Yes, eg JSON-P reference implementation

JSR 318

Interceptors 1.2

No

Yes as part of a CDI implementation

Jetty EE 6 Web Profile

Here is the matrix of JSRs for Java EE 6 Web Profile, and how they relate to Jetty:

Table 15. Java EE 6 Web Profile
JSR Name Included with jetty-9.0.x Pluggable

JSR 315

Servlet Specification API 3.0

Yes

JSR 314

JavaServer Faces 2.0 (JSF)

No

Yes, for example, Mojarra or MyFaces

JSR 245

JavaServer Pages 2.2/Java Expression Language 2.2 (JSP/EL)

Yes

Yes

JSR 52

Java Standard Tag Library 1.2 (JSTL)

Yes

Yes

JSR 45

Debugging Support for Other Languages 1.0

Yes (via JSP)

Yes (via JSP)

JSR 299

Contexts and Dependency Injection for the Java EE Platform 1.0 (Web Beans)

No

Yes, Weld or OpenWebBeans

JSR 330

Dependency Injection for Java 1.0

No

Yes as part of a CDI implementation, Weld

JSR 316

Managed Beans 1.0

No

Yes, as part of another technology.

JSR 318

Enterprise JavaBeans 3.1

No

Yes, OpenEJB

JSR 317

Java Persistence 2.0 (JPA)

No

Yes, Hibernate

JSR 250

Common Annotations for the Java Platform

Yes

Partially (for non-core Servlet Spec annotations)

JSR 907

Java Transaction API (JTA)

Yes

Implementations are pluggable, such as Atomikos, JOTM, Jencks (Geronimo Transaction Manager)

JSR 303

Bean Validation 1.0

No

Yes as part of another technology (JSF), or a stand-alone implementation such as Hiberate Validator

Finding Jetty in Maven

It is important that only stable releases are used in production environments. Versions that have been deprecated or are released as Milestones (M) or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets.

Maven Coordinates

Jetty has existed in Maven Central almost since its inception, though the coordinates have changed over the years. When Jetty was based at SourceForge and then The Codehaus it was located under the groupId of org.mortbay.jetty. With Jetty 7 the project moved to the Eclipse foundation and to a new groupId at that time to reflect its new home.

The top level Project Object Model (POM) for the Jetty project is located under the following coordinates.

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-project</artifactId>
  <version>${project.version}</version>
</dependency>

Changelogs in Maven Central

The changes between versions of Jetty are tracked in a file called VERSIONS.txt, which is under source control and is generated on release. Those generated files are also uploaded into Maven Central during the release of the top level POM. You can find them as a classifier marked artifact.

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-project</artifactId>
  <version>${project.version}</version>
  <classifier>version</classifier>
  <type>txt</type>
</dependency>

Using Jetty

You can use Jetty in many different ways ranging from embedding Jetty in applications, launching it from different build systems, from different JVM-based languages, or as a standalone distribution. This guide covers the latter, a standalone distribution suitable for deploying web applications.

Downloading Jetty

Downloading the Jetty Distribution

The standalone Jetty distribution is available for download from the Eclipse Foundation:

It is available in both zip and gzip formats; download the one most appropriate for your system. When you download and unpack the binary, it is extracted into a directory called jetty-home-VERSION. Put this directory in a convenient location. The rest of the instructions in this documentation refer to this location as either $JETTY_HOME or as $(jetty.home).

It is important that only stable releases are used in production environments. Versions that have been deprecated or are released as Milestones (M) or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets.
Distribution Content

A summary of the distribution’s contents follows. The top-level directory contains:

Table 16. Contents
Location Description

license-eplv10-aslv20.html

License file for Jetty

README.txt

Useful getting started information

VERSION.txt

Release information

bin/

Utility shell scripts to help run Jetty on Unix systems

demo-base/

A Jetty base directory to run a Jetty server with demonstration webapps

etc/

Directory for Jetty XML configuration files

lib/

All the JAR files necessary to run Jetty

logs/

Directory for request logs

modules/

Directory of module definitions

notice.html

License information and exceptions

resources/

Directory containing additional resources for classpath, activated via configuration

start.ini

File containing the arguments that are added to the effective command line (modules, properties and XML configuration files)

start.jar

Jar that invokes Jetty (see also Running Jetty)

webapps/

Directory containing webapps that run under the default configuration of Jetty

Downloading the Jetty-Home Distribution

Jetty-Home is an alternate version of the distribution that contains only the necessary items to host a Jetty distribution. It is intended for advanced users who are already familiar with Jetty and want to download a smaller distribution package. Jetty-Home can be downloaded from the Maven Central repository:

Like the main Jetty distribution, Jetty-Home is available in both zip and gzip formats; download the one most appropriate for your system. Notice that there are a number of other files with extensions of .sha or .md5 which are checksum files. When you download and unpack the binary, it is extracted into a directory called jetty-home-VERSION. Put this directory in a convenient location.

Distribution Content

A summary of the Jetty-Home’s distribution contents follows. The top-level directory contains:

Table 17. Contents
Location Description

license-eplv10-aslv20.html

License file for Jetty

VERSION.txt

Release information

etc/

Directory for Jetty XML configuration files

lib/

All the JAR files necessary to run Jetty

modules/

Directory of module definitions

notice.html

License information and exceptions

start.jar

Jar that invokes Jetty (see also Running Jetty)

Running Jetty

Once you have a copy of the Jetty distribution downloaded, extract the zip or tar.gz file to a location where you have read and write access. Jetty has no GUI (Graphical User Interface), so running the server and performing many configuration options is done from the command line.

Once you have access to your system’s command line, navigate to the directory where you unpacked your copy of the Jetty distribution. To start Jetty on the default port of 8080, run the following command:

$ java -jar start.jar
2017-09-20 15:45:11.986:INFO::main: Logging initialized @683ms to org.eclipse.jetty.util.log.StdErrLog
2017-09-20 15:45:12.197:WARN:oejs.HomeBaseWarning:main: This instance of Jetty is not running from a separate {jetty.base} directory, this is not recommended.  See documentation at https://eclipse.dev/jetty/documentation/
2017-09-20 15:45:12.243:INFO:oejs.Server:main: 12.0.9-SNAPSHOT
2017-09-20 15:45:12.266:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///installs/repository/jetty/webapps/] at interval 1
2017-09-20 15:45:12.298:INFO:oejs.AbstractConnector:main: Started ServerConnector@39c0f4a{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2017-09-20 15:45:12.298:INFO:oejs.Server:main: Started @995ms

You can point a browser at this server at http://localhost:8080. However, as there are no webapps deployed in the $JETTY_HOME directory, you will see a 404 error page served by Jetty. To stop the server, press CTRL + c or CTRL + z in your terminal.

Note the HomeBaseWarning - it is not recommended to run Jetty from the $JETTY_HOME directory. Instead, see how to create a Jetty Base below.

You will see examples throughout the documentation referencing $JETTY_HOME and $JETTY_BASE as well as {jetty.home} and {jetty.base}. These terms are used to refer to the location of your Jetty installation directories. Many users find it helpful to define $JETTY_HOME as an environment variable that maps to their Jetty distribution directory. More information can be found in our Administration section on managing Jetty Home and Jetty Base.

Demo Base

Within the standard Jetty distribution there is the demo-base directory. This is a fully-functioning Jetty Base (more on that later) complete with numerous web applications demonstrating different Jetty functionality. Additionally, the demo-base demonstrates the recommended way to run a Jetty base in a directory separate from $JETTY_HOME:

$ cd demo-base/
[my-base]$ java -jar /path/to/jetty-home/start.jar
2017-09-20 16:23:03.563:INFO::main: Logging initialized @429ms to org.eclipse.jetty.util.log.StdErrLog
2017-09-20 16:23:03.802:WARN::main: demo test-realm is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:03.804:INFO:oejs.Server:main: 12.0.9-SNAPSHOT
2017-09-20 16:23:03.819:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///installs/repository/jetty/demo-base/webapps/] at interval 1
2017-09-20 16:23:04.098:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=102ms
2017-09-20 16:23:04.103:WARN::main: async-rest webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:04.267:INFO:oejs.session:main: DefaultSessionIdManager workerName=node0
2017-09-20 16:23:04.267:INFO:oejs.session:main: No SessionScavenger set, using defaults
2017-09-20 16:23:04.268:INFO:oejs.session:main: Scavenging every 660000ms
2017-09-20 16:23:04.306:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@371a67ec{/async-rest,[file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-async-rest.war-_async-rest-any-5319296087878801290.dir/webapp/, jar:file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-async-rest.war-_async-rest-any-5319296087878801290.dir/webapp/WEB-INF/lib/example-async-rest-jar-12.0.9-SNAPSHOT.jar!/META-INF/resources],AVAILABLE}{/async-rest.war}
2017-09-20 16:23:04.429:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=53ms
2017-09-20 16:23:04.432:WARN::main: test webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:04.516:INFO:oejsh.ManagedAttributeListener:main: update QoSFilter null->org.eclipse.jetty.ee9.servlets.QoSFilter@7770f470 on o.e.j.w.WebAppContext@35e2d654{/test,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test.war-_test-any-6279588879522983394.dir/webapp/,STARTING}{/test.war}
2017-09-20 16:23:04.519:WARN:oeju.DeprecationWarning:main: Using @Deprecated Class org.eclipse.jetty.ee9.servlets.MultiPartFilter
2017-09-20 16:23:04.549:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@35e2d654{/test,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test.war-_test-any-6279588879522983394.dir/webapp/,AVAILABLE}{/test.war}
2017-09-20 16:23:04.646:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=12ms
2017-09-20 16:23:04.649:WARN::main: test-jndi webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:04.697:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@561b6512{/test-jndi,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-jndi.war-_test-jndi-any-6023636263414992288.dir/webapp/,AVAILABLE}{/test-jndi.war}
2017-09-20 16:23:04.770:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=40ms
2017-09-20 16:23:05.036:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@2beee7ff{/proxy,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-javadoc-proxy.war-_javadoc-proxy-any-2758874759195597975.dir/webapp/,AVAILABLE}{/javadoc-proxy.war}
2017-09-20 16:23:05.072:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=16ms
2017-09-20 16:23:05.074:WARN::main: test-jaas webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:05.098:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@506ae4d4{/test-jaas,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-jaas.war-_test-jaas-any-8067423971450448377.dir/webapp/,AVAILABLE}{/test-jaas.war}
2017-09-20 16:23:05.182:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=37ms
2017-09-20 16:23:05.184:WARN::main: test-spec webapp is deployed. DO NOT USE IN PRODUCTION!
2017-09-20 16:23:05.243:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@45099dd3{/test-spec,[file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-spec.war-_test-spec-any-1205866915335004234.dir/webapp/, jar:file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-spec.war-_test-spec-any-1205866915335004234.dir/webapp/WEB-INF/lib/test-web-fragment-12.0.9-SNAPSHOT.jar!/META-INF/resources],AVAILABLE}{/test-spec.war}
2017-09-20 16:23:05.247:INFO:oejsh.ContextHandler:main: Started o.e.j.s.h.MovedContextHandler@3e08ff24{/oldContextPath,null,AVAILABLE}
2017-09-20 16:23:05.274:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=18ms
2017-09-20 16:23:05.296:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@5ddeb7cb{/,file:///installs/repository/jetty/demo-base/webapps/ROOT/,AVAILABLE}{/ROOT}
2017-09-20 16:23:05.326:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=21ms
2017-09-20 16:23:05.352:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@6b695b06{/doc,file:///installs/repository/jetty/demo-base/webapps/doc/,AVAILABLE}{/doc}
2017-09-20 16:23:05.370:INFO:oejs.AbstractConnector:main: Started ServerConnector@28cda624{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2017-09-20 16:23:05.380:INFO:oejus.SslContextFactory:main: x509=X509@126253fd(jetty,h=[jetty.eclipse.org],w=[]) for SslContextFactory@57db2b13(file:///installs/repository/jetty/demo-base/etc/keystore,file:///installs/repository/jetty/demo-base/etc/keystore)
2017-09-20 16:23:05.381:INFO:oejus.SslContextFactory:main: x509=X509@475c9c31(mykey,h=[],w=[]) for SslContextFactory@57db2b13(file:///installs/repository/jetty/demo-base/etc/keystore,ffile:///installs/repository/jetty/demo-base/etc/keystore)
2017-09-20 16:23:05.523:INFO:oejs.AbstractConnector:main: Started ServerConnector@53f3bdbd{SSL,[ssl, http/1.1]}{0.0.0.0:8443}
2017-09-20 16:23:05.524:INFO:oejs.Server:main: Started @2390ms

You can visit this demo server by pointing a browser at http://localhost:8080, which will now show a welcome page and several demo/test web applications.

The demonstration web applications are not necessarily secure and should not be deployed in production web servers.

You can see the configuration of the demo-base by using the following commands:

> cd $JETTY_HOME/demo-base/
> java -jar $JETTY_HOME/start.jar --list-modules
...

> java -jar $JETTY_HOME/start.jar --list-config
...

The --list-modules command will return a complete list of available and enabled modules for the server. It will also display the location of the modules, how and in what order they are implemented, dependent modules, and associated jar files.

The --list-config command displays a trove of information about the server including the Java and Jetty environments, the configuration order, any JVM arguments or System Properties set, general server properties, a full listing of the Jetty server class path, and active Jetty XML files.

Common Jetty Configuration

Creating a new Jetty Base

The demo-base directory described earlier is an example of the jetty.base mechanism. A Jetty base directory allows the configuration and web applications of a server instance to be stored separately from the Jetty distribution, so that upgrades can be done with minimal disruption. Jetty’s default configuration is based on two properties:

jetty.home

The property that defines the location of the Jetty distribution, its libs, default modules and default XML files (typically start.jar, lib, etc).

jetty.base

The property that defines the location of a specific implementation of a Jetty server, its configuration, logs and web applications (typically start.d/*.ini files, logs and webapps).

Your Jetty Home directory should be treated as a standard of truth and remain unmodified or changed. Changes or additions to your configuration should take place in the Jetty Base directory.

The jetty.home and jetty.base properties may be explicitly set on the command line, or they can be inferred from the environment if used with commands like:

> cd $JETTY_BASE
> java -jar $JETTY_HOME/start.jar

The following commands create a new base directory, enables both the HTTP connector and the web application deployer modules, and copies a demo webapp to be deployed:

> JETTY_BASE=/tmp/mybase
> mkdir $JETTY_BASE
> cd $JETTY_BASE
> java -jar $JETTY_HOME/start.jar

WARNING: Nothing to start, exiting ...

Usage: java -jar start.jar [options] [properties] [configs]
       java -jar start.jar --help  # for more information

> java -jar $JETTY_HOME/start.jar --create-startd
INFO : Base directory was modified
> java -jar $JETTY_HOME/start.jar --add-to-start=http,deploy

INFO: server          initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO: http            initialised in ${jetty.base}/start.d/http.ini
INFO: security        initialised (transitively) in ${jetty.base}/start.d/security.ini
INFO: servlet         initialised (transitively) in ${jetty.base}/start.d/servlet.ini
INFO: webapp          initialised (transitively) in ${jetty.base}/start.d/webapp.ini
INFO: deploy          initialised in ${jetty.base}/start.d/deploy.ini
MKDIR: ${jetty.base}/webapps
INFO: Base directory was modified

> cp $JETTY_HOME/demo-base/webapps/async-rest.war webapps/ROOT.war
> java -jar $JETTY_HOME/start.jar

2015-06-04 11:10:16.286:INFO::main: Logging initialized @274ms
2015-06-04 11:10:16.440:INFO:oejs.Server:main: jetty-9.3.0.v20150601
2015-06-04 11:10:16.460:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///tmp/mybase/webapps/] at interval 1
2015-06-04 11:10:16.581:WARN::main: async-rest webapp is deployed. DO NOT USE IN PRODUCTION!
2015-06-04 11:10:16.589:INFO:oejw.StandardDescriptorProcessor:main: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
2015-06-04 11:10:16.628:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@1a407d53{/,[file:///tmp/jetty-0.0.0.0-8080-ROOT.war-_-any-4510228025526425427.dir/webapp/, jar:file:///tmp/jetty-0.0.0.0-8080-ROOT.war-_-any-4510228025526425427.dir/webapp/WEB-INF/lib/example-async-rest-jar-12.0.9-SNAPSHOT.jar!/META-INF/resources],AVAILABLE}{/ROOT.war}
2015-06-04 11:10:16.645:INFO:oejs.ServerConnector:main: Started ServerConnector@3abbfa04{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2015-06-04 11:10:16.646:INFO:oejs.Server:main: Started @634ms

Changing the Jetty Port

You can configure Jetty to run on a different port by setting the jetty.http.port property on the command line:

> cd $JETTY_BASE
> java -jar $JETTY_HOME/start.jar jetty.http.port=8081
...

When the server starts, it will now run on port 8081. It is important to note that setting properties on the command line will only take affect for that instance of the server. To change the configuration so that the server will always start on the desired port, you will need to edit the start.d/http.ini

The configuration by properties works via the following chain:

  • The start.d/http.ini file is part of the effective command line and contains the --module=http argument which activates the http module.

  • The modules/http.mod file defines the http module which specifies the etc/jetty-http.xml configuration file and the template ini properties it uses.

  • The jetty.http.port property is used by the Property XML element in etc/jetty.http.xml to inject the ServerConnector instance with the port.

For more information see the Quickstart Configuration Guide and Configuring Connectors.

Adding SSL for HTTPS & HTTP2

Building on the example above, we can activate additional modules to add support HTTPS and HTTP2 for the server. To add HTTPS and HTTP2 connectors to a Jetty configuration, the modules can be activated by the following command:

> java -jar $JETTY_HOME/start.jar --add-to-start=https,http2

ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
 + contains software not provided by the Eclipse Foundation!
 + contains software not covered by the Eclipse Public License!
 + has not been audited for compliance with its license

 Module: alpn-impl/alpn-8
  + ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
  + ALPN replaces/modifies OpenJDK classes in the sun.security.ssl package.
  + http://github.com/jetty-project/jetty-alpn
  + http://openjdk.java.net/legal/gplv2+ce.html

Proceed (y/N)? y
INFO  : alpn-impl/alpn-1.8.0_92 dynamic dependency of alpn-impl/alpn-8
INFO  : alpn            transitively enabled, ini template available with --add-to-start=alpn
INFO  : alpn-impl/alpn-8 dynamic dependency of alpn
INFO  : http2           initialized in ${jetty.base}/start.d/http2.ini
INFO  : https           initialized in ${jetty.base}/start.d/https.ini
INFO  : ssl             transitively enabled, ini template available with --add-to-start=ssl
MKDIR : ${jetty.base}/lib/alpn
DOWNLD: https://repo1.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.8.v20160420/alpn-boot-8.1.8.v20160420.jar to ${jetty.base}/lib/alpn/alpn-boot-8.1.8.v20160420.jar
MKDIR : ${jetty.base}/etc
COPY  : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
INFO  : Base directory was modified

> java -jar $JETTY_HOME/start.jar
[...]
2017-05-22 12:48:23.271:INFO:oejs.AbstractConnector:main: Started ServerConnector@134d0064{SSL,[ssl, alpn, h2, http/1.1]}{0.0.0.0:8443}
[...]

The --add-to-start command sets up the effective command line in the ini files to run an ssl connection that supports the HTTPS and HTTP2 protocols as follows:

  • transitively enabled the ssl module that configures an SSL connector (eg port, keystore etc.) by adding etc/jetty-ssl.xml and etc/jetty-ssl-context.xml to the effective command line.

  • transitively enabled the alpn module that configures protocol negotiation on the SSL connector by adding etc/jetty-alpn.xml to the effective command line.

  • creates start.d/https.ini that configures the HTTPS protocol on the SSL connector by adding etc/jetty-https.xml to the effective command line.

  • creates start.d/http2.ini that configures the HTTP/2 protocol on the SSL connector by adding etc/jetty-http2.xml to the effective command line.

  • checks for the existence of a etc/keystore file and if not present, downloads a demonstration keystore file.

Changing the Jetty HTTPS Port

You can configure the SSL connector to run on a different port by setting the jetty.ssl.port property on the command line:

> cd $JETTY_BASE
> java -jar $JETTY_HOME/start.jar jetty.ssl.port=8444

Alternatively, property values can be added to the effective command line built from the start.ini file or start.d/*.ini files, depending on your set up. Please see the section on Start.ini vs. Start.d for more information.

More start.jar Options

The job of the start.jar is to interpret the command line, start.ini and start.d directory (and associated .ini files) to build a Java classpath and list of properties and configuration files to pass to the main class of the Jetty XML configuration mechanism. The start.jar mechanism has many options which are documented in the Starting Jetty administration section and you can see them in summary by using the command:

> java -jar $JETTY_HOME/start.jar --help

An Introduction to Jetty Configuration

What to Configure in Jetty

This section gives an overview of the components of Jetty you typically configure using the mechanisms outlined in the previous section. [basic-architecture] describes the structure of a Jetty server, which is good background reading to understand configuration, and is vital if you want to change the structure of the server as set up by the default configurations in the Jetty distribution. However, for most purposes, configuration is a matter of identifying the correct configuration file and modifying existing configuration values.

Configuring the Server

The Server instance is the central coordination object of a Jetty server; it provides services and life cycle management for all other Jetty server components. In the standard Jetty distribution, the core server configuration is in etc/jetty.xml file, but you can mix in other server configurations which can include:

ThreadPool

The Server instance provides a ThreadPool instance that is the default Executor service other Jetty server components use. The prime configuration of the thread pool is the maximum and minimum size and is set in start.ini or start.d/server.ini.

Handlers

A Jetty server can have only a single Handler instance to handle incoming HTTP requests. However a handler may be a container or wrapper of other handlers forming a tree of handlers that typically handle a request as a collaboration between the handlers from a branch of the tree from root to leaf. The default handler tree set up in the etc/jetty.xml file is a Handler Collection containing a Context Handler Collection and the Default Handler. The Context Handler Collection selects the next handler by context path and is where deployed Context Handler and Web Application Contexts are added to the handler tree. The Default Handler handles any requests not already handled and generates the standard 404 page. Other configuration files may add handlers to this tree (for example, jetty-rewrite.xml, jetty-requestlog.xml) or configure components to hot deploy handlers (for example, jetty-deploy.xml).

Server Attributes

The server holds a generic attribute map of strings to objects so that other Jetty components can associate named objects with the server, and if the value objects implement the LifeCycle interface, they are started and stopped with the server. Typically server attributes hold server-wide default values.

Server fields

The server also has some specific configuration fields that you set in start.ini or start.d/server.ini for controlling, among other things, the sending of dates and versions in HTTP responses.

Connectors

The server holds a collection of connectors that receive connections for HTTP and the other protocols that Jetty supports. The next section, Configuring Connectors describes configuration of the connectors themselves. For the server you can either set the collection of all connectors or add/remove individual connectors.

Services

The server can hold additional service objects, sometimes as attributes, but often as aggregated LifeCycle beans. Examples of services are Login Services and DataSources, which you configure at the server level and then inject into the web applications that use them.

Configuring Connectors

A Jetty Server Connector is a network end point that accepts connections for one or more protocols which produce requests and/or messages for the Jetty server. In the standard Jetty server distribution, several provided configuration files add connectors to the server for various protocols and combinations of protocols: http.ini, https.ini and jetty-http2.xml. The configuration needed for connectors is typically:

Port

The TCP/IP port on which the connector listens for connections is set using the the XML Property element which looks up the jetty.http.port (or jetty.ssl.port) property, and if not found defaults to 8080 (or 8443 for TLS).

Host

You can configure a host either as a host name or IP address to identify a specific network interface on which to listen. If not set, or set to the value of 0.0.0.0, the connector listens on all local interfaces. The XML Property element is used to look up the host value from the jetty.host property.

Idle Timeout

The time in milliseconds that a connection can be idle before the connector takes action to close the connection.

HTTP Configuration

Connector types that accept HTTP semantics (including HTTP, HTTPS and HTTP2) are configured with a HttpConfiguration instance that contains common HTTP configuration that is independent of the specific wire protocol used. Because these values are often common to multiple connector types, the standard Jetty Server distribution creates a single HttpConfiguration in the jetty.xml file which is used via the XML Ref element in the specific connector files.

SSL Context Factory

The TLS connector types (HTTPS and HTTP2) configure an SSL Context Factory with the location of the server keystore and truststore for obtaining server certificates.

Virtual hosts are not configured on connectors. You must configure individual contexts with the virtual hosts to which they respond.
Prior to Jetty 9, the type of the connector reflected both the protocol supported (HTTP, HTTPS, AJP, SPDY), and the nature of the implementation (NIO or BIO). From Jetty 9 onwards there is only one prime Connector type (ServerConnector), which is NIO based and uses Connection Factories to handle one or more protocols.

Configuring Contexts

A Jetty context is a handler that groups other handlers under a context path together with associated resources and is roughly equivalent to the standard ServletContext API. A context may contain either standard Jetty handlers or a custom application handler.

The servlet specification defines a web application. In Jetty a standard web application is a specialized context that uses a standard layout and WEB-INF/web.xml to instantiate and configure classpath, resource base and handlers for sessions, security, and servlets, plus servlets for JSPs and static content. Standard web applications often need little or no additional configuration, but you can also use the techniques for arbitrary contexts to refine or modify the configuration of standard web applications.

Configuration values that are common to all contexts are:

contextPath

The contextPath is a URL prefix that identifies which context a HTTP request is destined for. For example, if a context has a context path /foo, it handles requests to /foo, /foo/index.html, /foo/bar/, and /foo/bar/image.png but it does not handle requests like /, /other/, or /favicon.ico. A context with a context path of / is called the root context.

The context path can be set by default from the deployer (which uses the filename as the basis for the context path); or in code; or it can be set by a Jetty IoC XML that is either applied by the deployer or found in the WEB-INF/jetty-web.xml file of a standard web app context.

virtualHost

A context may optionally have one or more virtual hosts set. Unlike the host set on a connector (which selects the network interface on which to listen), a virtual host does not set any network parameters. Instead a virtual host represents an alias assigned by a name service to an IP address, which may have many aliases. To determine which virtual host a request is intended for, the HTTP client (browser) includes in the request the name used to look up the network address. A context with a virtual host set only handles requests that have a matching virtual host in their request headers.

classPath

A context may optionally have a classpath, so that any thread that executes a handler within the context has a thread context classloader set with the classpath. A standard web application has the classpath initialized by the WEB-INF/lib and WEB-INF/classes directory and has additional rules about delegating classloading to the parent classloader. All contexts may have additional classpath entries added.

attributes

Attributes are arbitrary named objects that are associated with a context and are frequently used to pass entities between a web application and its container. For example the attribute jakarta.servlet.context.tempdir is used to pass the File instance that represents the assigned temporary directory for a web application.

resourceBase

The resource base is a directory (or collection of directories or URL) that contains the static resources for the context. These can be images and HTML files ready to serve or JSP source files ready to be compiled. In traditional web servers this value is often called the docroot.

Context Configuration by API

In an embedded server, you configure contexts by directly calling the ContextHandler API as in the following example:

Unresolved directive in gettingstarted/configuring/what-to-configure.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneContext.java[]
Context Configuration by IoC XML

You can create and configure a context entirely by IoC XML (either Jetty’s or Spring). The deployer discovers and hot deploys context IoC descriptors like the following which creates a context to serve the Javadoc from the Jetty distribution:

<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<!--
  Configure a custom context for serving javadoc as static resources
-->

<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
  <Set name="contextPath">/javadoc</Set>
  <Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/javadoc/</Set>
  <Set name="handler">
    <New class="org.eclipse.jetty.server.handler.ResourceHandler">
      <Set name="welcomeFiles">
        <Array type="String">
          <Item>index.html</Item>
        </Array>
      </Set>
      <Set name="cacheControl">max-age=3600,public</Set>
    </New>
  </Set>
</Configure>
Configuring Web Applications

The servlet specification defines a web application, which when packaged as a zip is called WAR file (Web application ARchive). Jetty implements both WAR files and unpacked web applications as a specialized context that is configured by means of:

  • A standard layout which sets the location of the resourceBase (the root of the WAR) and initializes the classpath from jars found in WEB-INF/lib and classes found in WEB-INF/classes.

  • The standard WEB-INF/web.xml deployment descriptor which is parsed to define and configure init parameters, filters, servlets, listeners, security constraints, welcome files and resources to be injected.

  • A default web.xml format deployment descriptor provided either by Jetty or in configuration configures the JSP servlet and the default servlet for handling static content. The standard web.xml may override the default web.xml.

  • Annotations discovered on classes in Jars contained in WEB-INF/lib can declare additional filters, servlets and listeners.

  • Standard deployment descriptor fragments discovered in Jars contained in WEB-INF/lib can declare additional init parameters, filters, servlets, listeners, security constraints, welcome files and resources to be injected.

  • An optional WEB-INF/jetty-web.xml file may contain Jetty IoC configuration to configure the Jetty specific APIs of the context and handlers.

Because these configuration mechanisms are contained within the WAR file (or unpacked web application), typically a web application contains much of its own configuration and deploying a WAR is often just a matter of dropping the WAR file in to the webapps directory that is scanned by the Jetty deployer.

If you need to configure something within a web application, often you do so by unpacking the WAR file and editing the web.xml and other configuration files. However, both the servlet standard and some Jetty features allow for other configuration to be applied to a web application externally from the WAR:

  • Configured data sources and security realms in the server can be injected into a web application either explicitly or by name matching.

  • Jetty allows one or more override deployment descriptors, in web.xml format, to be set on a context (via code or IoC XML) to amend the configuration set by the default and standard web.xml.

  • The normal Jetty Java API may be called by code or IoC XML to amend the configuration of a web application.

Setting the Context Path

The web application standard provides no configuration mechanism for a web application or WAR file to set its own contextPath. By default the deployer uses conventions to set the context path: If you deploy a WAR file called foobar.WAR, the context path is /foobar; if you deploy a WAR file called ROOT.WAR the context path is /.

However, it is often desirable to explicitly set the context path so that information (for example, version numbers) may be included in the filename of the WAR. Jetty allows the context Path of a WAR file to be set internally (by the WAR itself) or externally (by the deployer of the WAR).

To set the contextPath from within the WAR file, you can include a WEB-INF/jetty-web.xml file which contains IoC XML to set the context path:

<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
    <Set name="contextPath">/contextpath</Set>
</Configure>

Alternately, you can configure the classpath externally without the need to modify the WAR file itself. Instead of allowing the WAR file to be discovered by the deployer, an IoC XML file may be deployed that both sets the context path and declares the WAR file that it applies to:

<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test.war</Set>
  <Set name="contextPath">/test</Set>
</Configure>

An example of setting the context path is included with the Jetty distribution in $JETTY_HOME/webapps/test.xml.

Web Application Deployment

Jetty is capable of deploying a variety of Web Application formats. This is accomplished via scans of the ${jetty.base}/webapps directory for contexts to deploy.

A Context can be any of the following:

  • A standard WAR file. (must in “.war”).

  • A directory containing an expanded WAR file. (must contain {dir}/WEB-INF/web.xml file).

  • A directory containing static content.

  • A XML descriptor in [jetty-xml-syntax] that configures a ContextHandler instance (Such as a WebAppContext).

The new WebAppProvider will attempt to avoid double deployments during the directory scan with the following heuristics:

  • Hidden files (starting with ".") are ignored

  • Directories with names ending in ".d" are ignored

  • If a directory and matching WAR file exist with the same base name (eg: foo/ and foo.war), then the directory is assumed to be the unpacked WAR and only the WAR is deployed (which may reuse the unpacked directory)

  • If a directory and matching XML file exists (eg: foo/ and foo.xml), then the directory is assumed to be an unpacked WAR and only the XML is deployed (which may use the directory in its own configuration)

  • If a WAR file and matching XML file exist (eg: foo.war and foo.xml), then the WAR is assumed to be configured by the XML and only the XML is deployed.

In prior versions of Jetty there was a separate ContextDeployer that provided XML-based deployment. As of Jetty 9 the ContextDeployer no longer exists and its functionality has been merged with the new WebAppProvider to avoid double deployment scenarios.
Setting an Authentication Realm

The authentication method and realm name for a standard web application may be set in the web.xml deployment descriptor with elements like:

...
<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Test Realm</realm-name>
</login-config>
...

This example declares that the BASIC authentication mechanism will be used with credentials validated against a realm called "Test Realm." However the standard does not describe how the realm itself is implemented or configured. In Jetty, there are several realm implementations (called LoginServices) and the simplest of these is the HashLoginService, which can read usernames and credentials from a Java properties file.

To configure an instance of HashLoginService that matches the "Test Realm" configured above, the following $JETTY_BASE/etc/test-realm.xml IoC XML file should be passed on the command line or set in start.ini or start.d/server.ini.

Unresolved directive in gettingstarted/configuring/what-to-configure.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/test-realm.xml[]

This creates and configures the LoginService as an aggregate bean on the server. When a web application is deployed that declares a realm called "Test Realm," the server beans are searched for a matching Login Service.

Upgrading Jetty

Unresolved directive in gettingstarted/upgrading/chapter.adoc - include::upgrading-from-jetty-9.adoc[] Unresolved directive in index.adoc - include::http2/chapter.adoc[]

Jetty XML Reference

Jetty XML Usage

Jetty provides an XML-based configuration. It is grounded in Java’s Reflection API. Classes in the java.lang.reflect represent Java methods and classes, such that you can instantiate objects and invoke their methods based on their names and argument types. Behind the scenes, Jetty’s XML config parser translates the XML elements and attributes into Reflection calls.

Using jetty.xml

To use jetty.xml, specify it as a configuration file when running Jetty.

 java -jar start.jar etc/jetty.xml
If you start Jetty without specifying a configuration file, Jetty automatically locates and uses the default installation jetty.xml file. Therefore java -jar start.jar is equivalent to java -jar start.jar etc/jetty.xml .

Using Multiple Configuration Files

You are not limited to one configuration file; you can use multiple configuration files when running Jetty, and Jetty will configure the appropriate server instance. The ID of the server in the <Configure> tag specifies the instance you want to configure. Each server ID in a configuration file creates a new server instance within the same JVM. If you use the same ID across multiple configuration files, those configurations are all applied to the same server.

Setting Parameters in Configuration Files

You can set parameters in configuration files either with system properties (using <SystemProperty>) or properties files (using <Property>) passed via the command line. For example, this code in jetty.xml allows the port to be defined on the command line, falling back onto `8080`if the port is not specified:

  <Set name="port"><SystemProperty name="jetty.http.port" default="8080"/></Set>

Then you modify the port while running Jetty by using this command:

 java -Djetty.http.port=8888 -jar start.jar etc/jetty.xml

An example of defining both system properties and properties files from the command line:

 java -Djetty.http.port=8888 -jar start.jar myjetty.properties etc/jetty.xml etc/other.xml

jetty.xml

jetty.xml is the default configuration file for Jetty, typically located at $JETTY_HOME/etc/jetty.xml. Usually the jetty.xml configures:

  • 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.

Not all Jetty features are configured in jetty.xml. There are several optional configuration files that share the same format as jetty.xml and, if specified, concatenate to it. These configuration files are also stored in $JETTY_HOME/etc/, and examples of them are in Github Repository. The selection of which configuration files to use is controlled by start.jar and the process of merging configuration is described in Jetty XML Usage.

Root Element

jetty.xml configures an instance of the Jetty org.eclipse.jetty.server.Server.

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure id="Server" class="org.eclipse.jetty.server.Server">
 ...
</Configure>

Examples

$JETTY_HOME/etc contains the default jetty.xml, as well as other sample configuration files (jetty-*.xml) which can be passed to the server via the command line.

Additional Resources

  • [jetty-xml-syntax] –in-depth reference for Jetty-specific configuration XML syntax.

  • jetty.xml –configuration file for configuring the entire server

jetty-web.xml

jetty-web.xml is a Jetty configuration file that you can bundle with a specific web application. The format of jetty-web.xml is the same as jetty.xml – it is an XML mapping of the Jetty API.

This document offers an overview for using the jetty-web.xml configuration file. For a more in-depth look at the syntax, see [jetty-xml-syntax].

Root Element

jetty-web.xml applies on a per-webapp basis, and configures an instance of org.eclipse.jetty.ee9.webapp.WebAppContext.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
 ..
</Configure>
Make sure you are applying the configuration to an instance of the proper class. jetty-web.xml configures an instance of WebAppContext; jetty.xml configures an instance of Server.

Using jetty-web.xml

Place the jetty-web.xml into your web application’s WEB-INF folder. When Jetty deploys a web application, it looks for a file called WEB-INF/jetty-web.xml or WEB-INF/web-jetty.xml within the web application (or WAR) and applies the configuration found there. Be aware that jetty-web.xml is called after all other configuration has been applied to the web application.

It is important to note that jetty-web.xml files utilize the webapp classpath, not the classpath of the server.

jetty-web.xml Examples

The distribution contains an example of jetty-web.xml inside the WEB-INF folder of the test webapp WAR ($JETTY_HOME/demo-base/webapps/test.war/WEB-INF/jetty-web.xml).

Additional jetty-web.xml Resources

  • [jetty-xml-syntax] –in-depth reference for Jetty-specific configuration XML syntax.

  • jetty.xml –configuration file for configuring the entire server

jetty-env.xml

jetty-env.xml is an optional Jetty file that configures JNDI resources for an individual webapp. The format of jetty-env.xml is the same as jetty.xml –it is an XML mapping of the Jetty API.

When Jetty deploys a web application, it automatically looks for a file called ` WEB-INF/jetty-env.xml` within the web application (or WAR), and sets up the webapp naming environment so that naming references in the WEB-INF/web.xml file can be resolved from the information provided in the WEB-INF/jetty-env.xml and jetty.xml files. You define global naming resources on the server via jetty.xml.

jetty-env.xml Root Element

Jetty applies jetty-env.xml on a per-webapp basis, and configures an instance of org.eclipse.jetty.ee9.webapp.WebAppContext.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
 ..
</Configure>
Make sure you are applying the configuration to an instance of the proper class. jetty-env.xml configures an instance of WebAppContext, and not an instance of Server.

Using jetty-env.xml

Place the jetty-env.xml file in your web application’s WEB-INF folder.

 <?xml version="1.0"?>
 <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd">

 <Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">

   <!-- Add an EnvEntry only valid for this webapp               -->
   <New id="gargle"  class="org.eclipse.jetty.plus.jndi.EnvEntry">
     <Arg>gargle</Arg>
     <Arg type="java.lang.Double">100</Arg>
     <Arg type="boolean">true</Arg>
   </New>

  <!-- Add an override for a global EnvEntry                           -->
   <New id="wiggle"  class="org.eclipse.jetty.plus.jndi.EnvEntry">
     <Arg>wiggle</Arg>
     <Arg type="java.lang.Double">55.0</Arg>
     <Arg type="boolean">true</Arg>
   </New>

   <!-- an XADataSource                                                -->
   <New id="mydatasource99" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg>jdbc/mydatasource99</Arg>
     <Arg>
       <New class="com.atomikos.jdbc.SimpleDataSourceBean">
         <Set name="xaDataSourceClassName">org.apache.derby.jdbc.EmbeddedXADataSource</Set>
         <Set name="xaDataSourceProperties">databaseName=testdb99;createDatabase=create</Set>
         <Set name="UniqueResourceName">mydatasource99</Set>
       </New>
     </Arg>
   </New>

 </Configure>

Additional jetty-env.xml Resources

  • [jetty-xml-syntax] –In-depth reference for Jetty-specific configuration XML syntax.

  • jetty.xml –Configuration file for configuring the entire server.

webdefault.xml

The webdefault.xml file saves web applications from having to define a lot of house-keeping and container-specific elements in their own web.xml files. For example, you can use it to set up MIME-type mappings and JSP servlet-mappings. Jetty applies webdefault.xml to a web application before the application’s own WEB-INF/web.xml, which means that it cannot override values inside the webapp’s web.xml. It uses the jetty.xml syntax. Generally, it is convenient for all webapps in a Jetty instance to share the same webdefault.xml file. However, it is certainly possible to provide differentiated ` webdefault.xml` files for individual web applications.

The webdefault.xml file is located in $(jetty.home)/etc/webdefault.xml.

Using webdefault.xml

You can specify a custom configuration file to use for specific webapps, or for all webapps. If you do not specify an alternate defaults descriptor, the $JETTY-HOME/etc/jetty-deploy.xml file will configure jetty to automatically use $JETTY_HOME/etc/webdefault.xml.

To ensure your webdefault.xml files are validated, you will need to set the validateXml attribute to true as described here.

The webdefault.xml included with the Jetty Distribution contains several configuration options, such as init params and servlet mappings, and is separated into sections for easy navigation. Some of the more common options include, but are not limited to:

dirAllowed

If true, directory listings are returned if no welcome file is found. Otherwise 403 Forbidden displays.

precompressed

If set to a comma separated list of file extensions, these indicate compressed formats that are known to map to a MIME-type that may be listed in a requests Accept-Encoding header. If set to a boolean True, then a default set of compressed formats will be used, otherwise no pre-compressed formats.

maxCacheSize

Maximum total size of the cache or 0 for no cache.

maxCachedFileSize

Maximum size of a file to cache.

maxCachedFiles

Maximum number of files to cache.

Creating a Custom webdefault.xml for One WebApp

You can specify a custom webdefault.xml for an individual web application in that webapp’s jetty.xml as follows:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  ...
  <!-- Set up the absolute path to the custom webdefault.xml -->
  <Set name="defaultsDescriptor">/my/path/to/webdefault.xml</Set>
  ...
</Configure>

The equivalent in code is:

import org.eclipse.jetty.ee9.webapp.WebAppContext;

    ...

    WebAppContext wac = new WebAppContext();
    ...
    //Set up the absolute path to the custom webdefault.xml.
    wac.setDefaultsDescriptor("/my/path/to/webdefault.xml");
    ...

Alternatively, you can use a Jetty Classloading to find the resource representing your custom webdefault.xml.

Creating a Custom webdefault.xml for Multiple WebApps

If you want to apply the same custom webdefault.xml to a number of webapps, provide the path to the file in jetty.xml in the $JETTY_HOME/etc/jetty-deploy.xml file:

   <Set name="defaultsDescriptor"><Property name="jetty.home" default="." />/other/path/to/another/webdefault.xml</Set>
Using the Jetty Maven Plugin

Similarly, when using the Jetty Maven Plugin you provide a customized webdefault.xml file for your webapp as follows:

<project>
    ...
    <plugins>
        <plugin>
            ...
            <artifactId>jetty-maven-plugin</artifactId>
            <configuration>
                <webApp>
                  ...
                  <defaultsDescriptor>/my/path/to/webdefault.xml</defaultsDescriptor>
                </webApp>
            </configuration>
        </plugin>
        ...
    </plugins>
    ...
</project>
Additional Resources
  • jetty-web.xml –Reference for web.xml files

  • Jetty override-web.xml –Information for this web.xml -formatted file, applied after the webapp’s web.xml webapp.

  • jetty.xml –Reference for jetty.xml files

Jetty override-web.xml

To deploy a web application or WAR into different environments, most likely you will need to customize the webapp for compatibility with each environment. The challenge is to do so without changing the webapp itself. You can use a jetty.xml file for some of this work since it is not part of the webapp. But there are some changes that jetty.xml cannot accomplish, for example, modifications to servlet init-params and context init-params. Using webdefault.xml is not an option because Jetty applies webdefault.xml to a web application before the application’s own WEB-INF/web.xml, which means that it cannot override values inside the webapp’s ` web.xml`.

The solution is override-web.xml. It is a web.xml file that Jetty applies to a web application after the application’s own WEB-INF/web.xml, which means that it can override values or add new elements. This is defined on a per-webapp basis, using the [jetty-xml-syntax].

Using override-web.xml

You can specify the override-web.xml to use for an individual web application in a deployable xml file located in Jetty webapps folder . For example, if you had a webapp named MyApp, you would place a deployable xml file named myapp.xml in ${jetty.base}/webapps which includes an overrideDescriptor entry for the override-web.xml file.

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  ...
  <!-- Set up the path to the custom override descriptor,
  relative to your $(jetty.home) directory or to the current directory -->
  <Set name="overrideDescriptor"><SystemProperty name="jetty.home" default="."/>/my/path/to/override-web.xml</Set>
  ...
</Configure>

The equivalent in code is:

import org.eclipse.jetty.ee9.webapp.WebAppContext;

    ...

    WebAppContext wac = new WebAppContext();
    ...
    //Set the path to the override descriptor, based on your $(jetty.home) directory
    wac.setOverrideDescriptor(System.getProperty("jetty.home")+"/my/path/to/override-web.xml");
    ...

Alternatively, you can use the classloader (Jetty Classloading) to get the path to the override descriptor as a resource.

Using the Jetty Maven Plugin

Use the <overrideDescriptor> tag as follows:

<project>
    ...
    <plugins>
        <plugin>
            ...
            <artifactId>jetty-maven-plugin</artifactId>
            <configuration>
                <webAppConfig>
                  ...
                  <overrideDescriptor>src/main/resources/override-web.xml</overrideDescriptor>
                </webAppConfig>
            </configuration>
        </plugin>
        ...
    </plugins>
    ...
</project>

Additional Resources

  • webdefault.xml –Information for this web.xml -formatted file, applied before the webapp’s web.xml webapp.

  • jetty.xml –Reference for jetty.xml files Unresolved directive in index.adoc - include::jmx/chapter.adoc[]

Configuring JNDI

Jetty supports java:comp/env lookups in webapps. This is an optional feature for which some configuration is required.

Working with Jetty JNDI

Defining the web.xml

You can configure naming resources to reference in a web.xml file and access from within the java:comp/env naming environment of the webapp during execution. Specifically, you can configure support for the following web.xml elements:

<env-entry/>
<resource-ref/>
<resource-env-ref/>

Configuring env-entries shows you how to set up overrides for env-entry elements in web.xml, while Configuring resource-refs and resource-env-refs discusses how to configure support resources such as javax.sql.DataSource.

You can also plug a JTA javax.transaction.UserTransaction implementation into Jetty so that webapps can look up java:comp/UserTransaction to obtain a distributed transaction manager: see Configuring XA Transactions.

Declaring Resources

You must declare the objects you want bound into the Jetty environment so that you can then hook into your webapp via env-entry, resource-ref and resource-env-refs in web.xml. You create these bindings by using declarations of the following types:

org.eclipse.jetty.plus.jndi.EnvEntry

For env-entry type of entries

org.eclipse.jetty.plus.jndi.Resource

For all other type of resources

org.eclipse.jetty.plus.jndi.Transaction

For a JTA manager

org.eclipse.jetty.plus.jndi.Link

For the link between a web.xml resource name and a naming entry

Declarations of each of these types follow the same general pattern:

<New class="org.eclipse.jetty.plus.jndi.xxxx">
  <Arg><!-- scope --></Arg>
  <Arg><!-- name --></Arg>
  <Arg><!-- value --></Arg>
</New>

You can place these declarations into three different files, depending on your needs and the scope of the resources being declared.

Deciding Where to Declare Resources

You can define naming resources in three places:

jetty.xml

Naming resources defined in a jetty.xml file are scoped at either the JVM level or the Server level. The classes for the resource must be visible at the Jetty container level. If the classes for the resource only exist inside your webapp, you must declare it in a WEB-INF/jetty-env.xml file.

WEB-INF/jetty-env.xml

Naming resources in a WEB-INF/jetty-env.xml file are scoped to the web app in which the file resides. While you can enter JVM or Server scopes if you choose, we do not recommend doing so. The resources defined here may use classes from inside your webapp. This is a Jetty-specific mechanism.

Context xml file

Entries in a context xml file should be scoped at the level of the webapp to which they apply, although you can supply a less strict scoping level of Server or JVM if you choose. As with resources declared in a jetty.xml file, classes associated with the resource must be visible on the container’s classpath.

Scope of Resource Names

Naming resources within Jetty belong to one of three different scopes, in increasing order of restrictiveness:

JVM scope

The name is unique across the JVM instance, and is visible to all application code. You represent this scope by a null first parameter to the resource declaration. For example:

<New id="cf" class="org.eclipse.jetty.plus.jndi.Resource">
  <Arg></Arg>  <!-- empty arg -->
  <Arg>jms/connectionFactory</Arg>
  <Arg>
    <New class="org.apache.activemq.ActiveMQConnectionFactory">
       <Arg>vm://localhost?broker.persistent=false</Arg>
    </New>
  </Arg>
</New>
Server scope

The name is unique to a Server instance, and is only visible to code associated with that instance. You represent this scope by referencing the Server instance as the first parameter to the resource declaration. For example:

<Configure id="Server" class="org.eclipse.jetty.Server">
  <New id="cf" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid="Server"/></Arg>  <!-- reference to Server instance -->
    <Arg>jms/connectionFactory</Arg>
    <Arg>
      <New class="org.apache.activemq.ActiveMQConnectionFactory">
        <Arg>vm://localhost?broker.persistent=false</Arg>
      </New>
    </Arg>
  </New>
</Configure>
Webapp scope

The name is unique to the WebAppContext instance, and is only visible to code associated with that instance. You represent this scope by referencing the WebAppContext instance as the first parameter to the resource declaration. For example:

<Configure id='wac' class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <New id="cf" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid='wac'/></Arg> <!-- reference to WebAppContext -->
    <Arg>jms/connectionFactory</Arg>
    <Arg>
      <New class="org.apache.activemq.ActiveMQConnectionFactory">
        <Arg>vm://localhost?broker.persistent=false</Arg>
      </New>
    </Arg>
  </New>
</Configure>

What Can Be Bound as a Resource?

You can bind four types of objects into a Jetty JNDI reference:

Configuring JNDI

Configuring JNDI env-entries

Sometimes it is useful to pass configuration information to a webapp at runtime that you either cannot or cannot conveniently code into a web.xml env-entry. In such cases, you can use the org.eclipse.jetty.plus.jndi.EnvEntry class, and even override an entry of the same name in web.xml.

<New class="org.eclipse.jetty.plus.jndi.EnvEntry">
  <Arg></Arg>
  <Arg>mySpecialValue</Arg>
  <Arg type="java.lang.Integer">4000</Arg>
  <Arg type="boolean">true</Arg>
</New>

This example defines a virtual env-entry called mySpecialValue with value 4000 that is scoped to the JVM. It is put into JNDI at java:comp/env/mySpecialValue for every web app deployed. Moreover, the boolean argument indicates that this value overrides an env-entry of the same name in web.xml. If you don’t want to override, omit this argument, or set it to false.

The Servlet Specification allows binding only the following object types to an env-entry:

  • java.lang.String

  • java.lang.Integer

  • java.lang.Float

  • java.lang.Double

  • java.lang.Long

  • java.lang.Short

  • java.lang.Character

  • java.lang.Byte

  • java.lang.Boolean

That being said, Jetty is a little more flexible and allows you to also bind custom POJOs, javax.naming.References and javax.naming.Referenceables. Be aware that if you take advantage of this feature, your web application is not portable.

To use the env-entry configured above, use code in your servlet/filter/etc., such as:

import javax.naming.InitialContext;

public class MyClass {

  public void myMethod() {

    InitialContext ic = new InitialContext();
    Integer mySpecialValue = (Integer)ic.lookup("java:comp/env/mySpecialValue");
    ...
  }
}

Configuring resource-refs and resource-env-refs

You can configure any type of resource that you want to refer to in a web.xml file as a resource-ref or resource-env-ref, using the org.eclipse.jetty.plus.jndi.Resource type of naming entry. You provide the scope, the name of the object (relative to java:comp/env) and a POJO instance or a javax.naming.Reference instance or javax.naming.Referenceable instance.

The J2EE Specification recommends storing DataSources in java:comp/env/jdbc, JMS connection factories under java:comp/env/jms, JavaMail connection factories under java:comp/env/mail and URL connection factories under java:comp/env/url.

For example:

Table 18. DataSource Declaration Conventions
Resource Type Name in jetty.xml Environment Lookup

javax.sql.DataSource

jdbc/myDB

java:comp/env/jdbc/myDB

javax.jms.QueueConnectionFactory

jms/myQueue

java:comp/env/jms/myQueue

javax.mail.Session

mail/myMailService

java:comp/env/mail/myMailService

Configuring DataSources

Here is an example of configuring a javax.sql.DataSource. Jetty can use any DataSource implementation available on its classpath. In this example, the DataSource is from the Derby relational database, but you can use any implementation of a javax.sql.DataSource. This example configures it as scoped to a web app with the id of wac:

<Configure id='wac' class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <New id="myds" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid="wac"/></Arg>
    <Arg>jdbc/myds</Arg>
    <Arg>
      <New class="org.apache.derby.jdbc.EmbeddedDataSource">
        <Set name="DatabaseName">test</Set>
        <Set name="createDatabase">create</Set>
      </New>
    </Arg>
  </New>
</Configure>

The code above creates an instance of org.apache.derby.jdbc.EmbeddedDataSource, calls the two setter methods setDatabaseName("test"), and setCreateDatabase("create"), and binds it into the JNDI scope for the web app. If you do not have the appropriate resource-ref set up in your web.xml, it is available from application lookups as java:comp/env/jdbc/myds.

Here’s an example web.xml declaration for the datasource above:

<resource-ref>
  <res-ref-name>jdbc/myds</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

To look up your DataSource in your servlet/filter/etc.:

import javax.naming.InitialContext;
import javax.sql.DataSource;

public class MyClass {

  public void myMethod() {

    InitialContext ic = new InitialContext();
    DataSource myDS = (DataSource)ic.lookup("java:comp/env/jdbc/myds");

    ...
  }
}
Careful! When configuring Resources, ensure that the type of object you configure matches the type of object you expect to look up in java:comp/env. For database connection factories, this means that the object you register as a Resource must implement the javax.sql.DataSource interface.

For more examples of datasource configurations, see Datasource Examples.

Configuring JMS Queues, Topics and ConnectionFactories

Jetty can bind any implementation of the JMS destinations and connection factories. You just need to ensure the implementation Jars are available on Jetty’s classpath. Here is an example of binding an ActiveMQ in-JVM connection factory:

<Configure id='wac' class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <New id="cf" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid='wac'/></Arg>
    <Arg>jms/connectionFactory</Arg>
    <Arg>
      <New class="org.apache.activemq.ActiveMQConnectionFactory">
        <Arg>vm://localhost?broker.persistent=false</Arg>
      </New>
    </Arg>
  </New>
</Configure>

The entry in web.xml would be:

<resource-ref>
  <res-ref-name>jms/connectionFactory</res-ref-name>
  <res-type>javax.jms.ConnectionFactory</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

Configuring Mail

Jetty also provides infrastructure for access to javax.mail.Sessions from within an application:

<Configure id='wac' class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <New id="mail" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid="wac"/></Arg>
    <Arg>mail/Session</Arg>
    <Arg>
      <New class="org.eclipse.jetty.jndi.factories.MailSessionReference">
        <Set name="user">fred</Set>
        <Set name="password">OBF:1xmk1w261z0f1w1c1xmq</Set>
        <Set name="properties">
          <New class="java.util.Properties">
            <Put name="mail.smtp.host">XXX</Put>
            <Put name="mail.from">me@me</Put>
            <Put name="mail.debug">true</Put>
          </New>
        </Set>
      </New>
    </Arg>
  </New>
</Configure>

This setup creates an instance of the org.eclipse.jetty.jndi.factories.MailSessionReference class, calls it’s setter methods to set up the authentication for the mail system, and populates a set of Properties, setting them on the MailSessionReference instance. The result is that an application can look up java:comp/env/mail/Session at runtime and obtain access to a javax.mail.Session that has the necessary configuration to permit it to send email via SMTP.

As of Jetty 10, the javax.mail and javax.activation jar files are not included in the Jetty Distribution and will need to be downloaded separately from Maven Central.
You can set the password to be plain text, or use Jetty’s Secure Password Obfuscation (OBF:) mechanism to make the config file a little more secure from prying eyes. Remember that you cannot use the other Jetty encryption mechanisms of MD5 and Crypt because they do not allow you to recover the original password, which the mail system requires.

Configuring XA Transactions

If you want to perform distributed transactions with your resources, you need a transaction manager that supports the JTA interfaces, and that you can look up as java:comp/UserTransaction in your webapp. Jetty does not ship with one as standard, but you can plug in the one you prefer. You can configure a transaction manager using the JNDI Transaction object in a Jetty config file. The following example configures the Atomikos transaction manager:

<New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction">
  <Arg>
    <New class="com.atomikos.icatch.jta.J2eeUserTransaction"/>
  </Arg>
</New>

Generally, the name you set for your Resource should be the same name you use for it in web.xml. For example:

In a context xml file:

<Configure id='wac' class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <New id="myds" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid="wac"/></Arg>
    <Arg>jdbc/mydatasource</Arg>
    <Arg>
      <New class="org.apache.derby.jdbc.EmbeddedDataSource">
        <Set name="DatabaseName">test</Set>
        <Set name="createDatabase">create</Set>
      </New>
    </Arg>
  </New>
</Configure>

In a web.xml file:

<resource-ref>
  <res-ref-name>jdbc/mydatasource</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
  <injection-target>
    <injection-target-class>com.acme.JNDITest</injection-target-class>
    <injection-target-name>myDatasource</injection-target-name>
  </injection-target>
</resource-ref>

However, you can refer to it in web.xml by a different name, and link it to the name in your org.eclipse.jetty.plus.jndi.Resource by using an org.eclipse.jetty.plus.jndi.Link. For the example above, you can refer to the jdbc/mydatasource resource as jdbc/mydatasource1 as follows:

In a context xml file declare jdbc/mydatasource:

<Configure id='wac' class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <New id="myds" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid="wac"/></Arg>
    <Arg>jdbc/mydatasource</Arg>
    <Arg>
      <New class="org.apache.derby.jdbc.EmbeddedDataSource">
        <Set name="DatabaseName">test</Set>
        <Set name="createDatabase">create</Set>
      </New>
    </Arg>
  </New>
</Configure>

Then in a WEB-INF/jetty-env.xml file, link the name jdbc/mydatasource to the name you want to reference it as in web.xml, which in this case is jdbc/mydatasource1:

<New id="map1" class="org.eclipse.jetty.plus.jndi.Link">
  <Arg><Ref refid='wac'/></Arg>
  <Arg>jdbc/mydatasource1</Arg> <!-- name in web.xml -->
  <Arg>jdbc/mydatasource</Arg>  <!-- name in container environment -->
</New>

Now you can refer to jdbc/mydatasource1 in the web.xml like this:

<resource-ref>
  <res-ref-name>jdbc/mydatasource1</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
  <injection-target>
    <injection-target-class>com.acme.JNDITest</injection-target-class>
    <injection-target-name>myDatasource</injection-target-name>
  </injection-target>
</resource-ref>

This can be useful when you cannot change a JNDI resource directly in the web.xml but need to link it to a specific resource in your deployment environment.

Using JNDI with Jetty Embedded

Setting up the Classpath

In addition to the jars that you require for your application, and the jars needed for core Jetty, you will need to place the following jars onto your classpath:

jetty-jndi.jar
jetty-plus.jar

If you are using transactions, you will also need the javax.transaction api. You can obtain this jar here.

If you wish to use mail, you will also need the javax.mail api and implementation which you can download here. Note that this jar also requires the javax.activation classes, which is available at this link.

Example Code

Here is an example class that sets up some JNDI entries and deploys a webapp that references these JNDI entries in code. We’ll use some mocked up classes for the transaction manager and the DataSource in this example for simplicity:

import java.util.Properties;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.ee9.webapp.WebAppContext;

/**
 * ServerWithJNDI
 *
 *
 */
public class ServerWithJNDI
{
    public static void main(String[] args) throws Exception
    {

        //Create the server
        Server server = new Server(8080);

        //Enable parsing of jndi-related parts of web.xml and jetty-env.xml
        org.eclipse.jetty.ee9.webapp.Configuration.ClassList classlist = org.eclipse.jetty.ee9.webapp.Configuration.ClassList.setServerDefault(server);
        classlist.addAfter("org.eclipse.jetty.ee9.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration");

        //Create a WebApp
        WebAppContext webapp = new WebAppContext();
        webapp.setContextPath("/");
        webapp.setWar("./my-foo-webapp.war");
        server.setHandler(webapp);

        //Register new transaction manager in JNDI
        //At runtime, the webapp accesses this as java:comp/UserTransaction
        org.eclipse.jetty.plus.jndi.Transaction transactionMgr = new org.eclipse.jetty.plus.jndi.Transaction(new com.acme.MockUserTransaction());

        //Define an env entry with Server scope.
        //At runtime, the webapp accesses this as java:comp/env/woggle
        //This is equivalent to putting an env-entry in web.xml:
        //<env-entry>
        //  <env-entry-name>woggle</env-entry-name>
        //  <env-entry-type>java.lang.Integer</env-entry-type>
        //  <env-entry-value>4000</env-entry-value>
        //</env-entry>
        org.eclipse.jetty.plus.jndi.EnvEntry woggle = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "woggle", new Integer(4000), false);


        //Define an env entry with webapp scope.
        //At runtime, the webapp accesses this as java:comp/env/wiggle
        //This is equivalent to putting a web.xml entry in web.xml:
        //<env-entry>
        //  <env-entry-name>wiggle</env-entry-name>
        //  <env-entry-value>100</env-entry-value>
        //  <env-entry-type>java.lang.Double</env-entry-type>
        //</env-entry>
        //Note that the last arg of "true" means that this definition for "wiggle" would override an entry of the
        //same name in web.xml
        org.eclipse.jetty.plus.jndi.EnvEntry wiggle = new org.eclipse.jetty.plus.jndi.EnvEntry(webapp, "wiggle", new Double(100), true);

        //Register a reference to a mail service scoped to the webapp.
        //This must be linked to the webapp by an entry in web.xml:
        // <resource-ref>
        //  <res-ref-name>mail/Session</res-ref-name>
        //  <res-type>javax.mail.Session</res-type>
        //  <res-auth>Container</res-auth>
        // </resource-ref>
        //At runtime the webapp accesses this as java:comp/env/mail/Session
        org.eclipse.jetty.jndi.factories.MailSessionReference mailref = new org.eclipse.jetty.jndi.factories.MailSessionReference();
        mailref.setUser("CHANGE-ME");
        mailref.setPassword("CHANGE-ME");
        Properties props = new Properties();
        props.put("mail.smtp.auth", "false");
        props.put("mail.smtp.host","CHANGE-ME");
        props.put("mail.from","CHANGE-ME");
        props.put("mail.debug", "false");
        mailref.setProperties(props);
        org.eclipse.jetty.plus.jndi.Resource xxxmail = new org.eclipse.jetty.plus.jndi.Resource(webapp, "mail/Session", mailref);


        // Register a  mock DataSource scoped to the webapp
        //This must be linked to the webapp via an entry in web.xml:
        //<resource-ref>
        //  <res-ref-name>jdbc/mydatasource</res-ref-name>
        //  <res-type>javax.sql.DataSource</res-type>
        //  <res-auth>Container</res-auth>
        //</resource-ref>
        //At runtime the webapp accesses this as java:comp/env/jdbc/mydatasource
        org.eclipse.jetty.plus.jndi.Resource mydatasource = new org.eclipse.jetty.plus.jndi.Resource(webapp, "jdbc/mydatasource",
                                                                                                     new com.acme.MockDataSource());

        server.start();
        server.join();
    }
}

Datasource Examples

Here are examples of configuring a JNDI datasource for various databases.

Read Configuring DataSources in Configuring JNDI for more information about configuring datasources.

All of these examples correspond to a resource-ref in web.xml.

  <resource-ref>
     <description>My DataSource Reference</description>
     <res-ref-name>jdbc/DSTest</res-ref-name>
     <res-type>javax.sql.DataSource</res-type>
     <res-auth>Container</res-auth>
  </resource-ref>

These examples assume that all of the datasources are declared at the JVM scope, but you can use other scopes if desired. You can configure all JNDI resources in a jetty.xml file, a WEB-INF/jetty-env.xml file, or a context XML file. See the section Deciding Where to Declare Resources for more information.

You must provide Jetty with the libraries necessary to instantiate the datasource you have configured by putting the corresponding Jar in JETTY_HOME/lib/ext.

Pooling DataSources

Pooling datasources enables connection pooling, which lets you reuse an existing connection instead of creating a new connection to the database. This is highly efficient in terms of memory allocation and speed of the request to the database. We highly recommend this option for production environments.

The following is a list of the pooled datasource examples we have worked with in the past:

HikariCP

Connection pooling, available at HikariCP Download. All configuration options for HikariCP are described here: HikariCP documentation.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
       <New class="com.zaxxer.hikari.HikariDataSource">
         <Arg>
            <New class="com.zaxxer.hikari.HikariConfig">
               <Set name="minimumPoolSize">5</Set>
               <Set name="maximumPoolSize">20</Set>
               <Set name="dataSourceClassName">com.mysql.jdbc.jdbc2.optional.MysqlDataSource</Set>
               <Set name="username">jdbc.user</Set>
               <Set name="password">jdbc.pass</Set>
               <Call name="addDataSourceProperty">
                  <Arg>url</Arg>
                  <Arg>jdbc.url</Arg>
               </Call>
            </New>
         </Arg>
      </New>
    </Arg>
  </New>
BoneCP

Connection pooling, available at BoneCP Download. All configuration options for BoneCP are described here: BoneCP API.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
       <New class="com.jolbox.bonecp.BoneCPDataSource">
         <Set name="driverClass">com.mysql.jdbc.Driver</Set>
         <Set name="jdbcUrl">jdbc.url</Set>
         <Set name="username">jdbc.user</Set>
         <Set name="password">jdbc.pass</Set>
         <Set name="minConnectionsPerPartition">5</Set>
         <Set name="maxConnectionsPerPartition">50</Set>
         <Set name="acquireIncrement">5</Set>
         <Set name="idleConnectionTestPeriod">30</Set>
      </New>
    </Arg>
  </New>
c3p0

Connection pooling, available at c3p0 Jar.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
      <New class="com.mchange.v2.c3p0.ComboPooledDataSource">
         <Set name="driverClass">org.some.Driver</Set>
         <Set name="jdbcUrl">jdbc.url</Set>
         <Set name="user">jdbc.user</Set>
         <Set name="password">jdbc.pass</Set>
      </New>
     </Arg>
    </New>
DBCP

Connection pooling, available at dbcp Jar.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
         <New class="org.apache.commons.dbcp.BasicDataSource">
            <Set name="driverClassName">org.some.Driver</Set>
            <Set name="url">jdbc.url</Set>
            <Set name="username">jdbc.user</Set>
            <Set name="password">jdbc.pass</Set>
         </New>
         </New>
     </Arg>
    </New>
Atomikos 3.3.2+

Connection pooling + XA transactions.

   <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
      <Arg></Arg>
      <Arg>jdbc/DSTest</Arg>
      <Arg>
         <New class="com.atomikos.jdbc.AtomikosDataSourceBean">
            <Set name="minPoolSize">2</Set>
            <Set name="maxPoolSize">50</Set>
            <Set name="xaDataSourceClassName">com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</Set>
            <Set name="UniqueResourceName">DSTest</Set>
            <Get name="xaProperties">
               <Call name="setProperty">
                  <Arg>url</Arg>
                  <Arg>jdbc:mysql://localhost:3306/databasename</Arg>
               </Call>
               <Call name="setProperty">
                  <Arg>user</Arg>
                  <Arg>some_username</Arg>
               </Call>
               <Call name="setProperty">
                  <Arg>password</Arg>
                  <Arg>some_password</Arg>
               </Call>
            </Get>
         </New>
      </Arg>
    </New>
MySQL

Implements javax.sql.DataSource and javax.sql.ConnectionPoolDataSource.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
        <New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
           <Set name="Url">jdbc:mysql://localhost:3306/databasename</Set>
           <Set name="User">user</Set>
           <Set name="Password">pass</Set>
        </New>
     </Arg>
    </New>
PostgreSQL

Implements javax.sql.ConnectionPoolDataSource.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
        <New class="org.postgresql.ds.PGConnectionPoolDataSource">
           <Set name="User">user</Set>
           <Set name="Password">pass</Set>
           <Set name="DatabaseName">dbname</Set>
           <Set name="ServerName">localhost</Set>
           <Set name="PortNumber">5432</Set>

        </New>
     </Arg>
  </New>
DB2

Implements javax.sql.ConnectionPoolDataSource.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
        <New class="com.ibm.db2.jcc.DB2ConnectionPoolDataSource">
           <Set name="DatabaseName">dbname</Set>
           <Set name="User">user</Set>
           <Set name="Password">pass</Set>
           <Set name="ServerName">servername</Set>
           <Set name="PortNumber">50000</Set>
        </New>
     </Arg>
  </New>

Non-pooling DataSources

If you are deploying in a production environment, we highly recommend using a Pooling DataSource. Since that is not always an option we have a handful of examples for non-pooling datasources listed here as well.

The following is a list of the non-pooled datasource examples:

SQL Server 2000

Implements javax.sql.DataSource and javax.sql.ConnectionPoolDataSource.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
        <New class="net.sourceforge.jtds.jdbcx.JtdsDataSource">
           <Set name="User">user</Set>
           <Set name="Password">pass</Set>
           <Set name="DatabaseName">dbname</Set>
           <Set name="ServerName">localhost</Set>
           <Set name="PortNumber">1433</Set>
        </New>
     </Arg>
    </New>
Oracle 9i/10g

Implements javax.sql.DataSource and javax.sql.ConnectionPoolDataSource.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg></Arg>
    <Arg>jdbc/DSTest</Arg>
    <Arg>
      <New class="oracle.jdbc.pool.OracleDataSource">
        <Set name="DriverType">thin</Set>
        <Set name="URL">jdbc:oracle:thin:@fmsswdb1:10017:otcd</Set>
        <Set name="User">xxxx</Set>
        <Set name="Password">xxxx</Set>
        <Set name="connectionCachingEnabled">true</Set>
        <Set name="connectionCacheProperties">
          <New class="java.util.Properties">
            <Call name="setProperty">
              <Arg>MinLimit</Arg>
              <Arg>5</Arg>
            </Call>
            <!-- put the other properties in here too -->
          </New>
        </Set>
      </New>
    </Arg>
  </New>

For more information, refer to: Oracle Database JDBC documentation.

PostgreSQL

Implements javax.sql.DataSource.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
        <New class="org.postgresql.ds.PGSimpleDataSource">
           <Set name="User">user</Set>
           <Set name="Password">pass</Set>
           <Set name="DatabaseName">dbname</Set>
           <Set name="ServerName">localhost</Set>
           <Set name="PortNumber">5432</Set>
        </New>
     </Arg>
  </New>
Sybase

Implements javax.sql.DataSource.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
        <New class="com.sybase.jdbc2.jdbc.SybDataSource">
           <Set name="DatabaseName">dbname</Set>
           <Set name="User">user</Set>
           <Set name="Password">pass</Set>
           <Set name="ServerName">servername</Set>
           <Set name="PortNumber">5000</Set>
        </New>
     </Arg>
  </New>
DB2

Implements javax.sql.DataSource.

  <New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
     <Arg></Arg>
     <Arg>jdbc/DSTest</Arg>
     <Arg>
        <New class="com.ibm.db2.jcc.DB2SimpleDataSource">
           <Set name="DatabaseName">dbname</Set>
           <Set name="User">user</Set>
           <Set name="Password">pass</Set>
           <Set name="ServerName">servername</Set>
           <Set name="PortNumber">50000</Set>
        </New>
     </Arg>
  </New>

Configuring JSP Support

Configuring JSP

This document provides information about configuring Java Server Pages (JSP) for Jetty.

Which JSP Implementation

Jetty uses Jasper from Apache as the default JSP container implementation.

By default the Jetty distribution enables the JSP module, and by default, this module is set to Apache Jasper.

Unresolved directive in jsp/configuring-jsp.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../jetty-home/src/main/resources/modules/jsp.mod[]

Note that the availability of some JSP features may depend on which JSP container implementation you are using. Note also that it may not be possible to precompile your JSPs with one container and deploy to the other.

Logging

The Apache Jasper logging system is bridged to the jetty logging system. Thus, you can enable logging for jsps in the same way you have setup for your webapp. For example, assuming you are using Jetty’s default StdErr logger, you would enable DEBUG level logging for jsps by adding the system property -Dorg.apache.jasper.LEVEL=DEBUG to the command line.

JSPs and Embedding

If you have an embedded setup for your webapp and wish to use JSPs, you will need to ensure that a JSP engine is correctly initialized.

For Apache, a Servlet Specification 3.1 style ServletContainerInitializer is used to accomplish this. You will need to ensure that this ServletContainerInitializer is run by jetty. Perhaps the easiest way to do this is to enable annotations processing so that Jetty automatically discovers and runs it. The Embedded Examples section includes a worked code example of how to do this.

Alternatively, you can manually wire in the appropriate ServletContainerInitializer as shown in the embedded-jetty-jsp example on GitHub, in which case you will not need the jetty-annotations jar on your classpath, nor include the AnnotationConfiguration in the list of configuration classes.

Precompiling JSPs

You can either follow the instructions on precompilation provided by Apache, or if you are using Maven for your builds, you can use the jetty-jspc-maven plugin to do it for you.

If you have precompiled your JSPs, and have customized the output package prefix (which is org.apache.jsp by default), you should configure your webapp context to tell Jetty about this custom package name. You can do this using a servlet context init-param called org.eclipse.jetty.ee9.servlet.jspPackagePrefix.

For example, suppose you have precompiled your JSPs with the custom package prefix of com.acme, then you would add the following lines to your web.xml file:

  <context-param>
    <param-name>org.eclipse.jetty.ee9.servlet.jspPackagePrefix</param-name>
    <param-value>com.acme</param-value>
  </context-param>
Both Jetty Maven plugins - jetty-jspc-maven-plugin and the jetty-maven-plugin - will only use Apache Jasper.
Apache JSP Container

By default, the Apache JSP container will look for the Eclipse Java Compiler (jdt). The Jetty distribution ships a copy of this in {$jetty.home}/lib/apache-jsp. If you wish to use a different compiler, you will need to configure the compilerClassName init-param on the JspServlet with the name of the class.

Table 19. Understanding Apache JspServlet Parameters
init param Description Default webdefault.xml

checkInterval

If non-zero and development is false, background jsp recompilation is enabled. This value is the interval in seconds between background recompile checks.

0

–

classpath

The classpath is dynamically generated if the context has a URL classloader. The org.apache.catalina.jsp_classpath context attribute is used to add to the classpath, but if this is not set, this classpath configuration item is added to the classpath instead.`

-

–

classdebuginfo

Include debugging info in class file.

TRUE

–

compilerClassName

If not set, defaults to the Eclipse jdt compiler.

-

–

compiler

Used if the Eclipse jdt compiler cannot be found on the classpath. It is the classname of a compiler that Ant should invoke.

–

–

compilerTargetVM

Target vm to compile for.

1.8

1.8

compilerSourceVM

Sets source compliance level for the jdt compiler.

1.8

1.8

development

If true recompilation checks occur at the frequency governed by modificationTestInterval.

TRUE

–

displaySourceFragment

Should a source fragment be included in exception messages

TRUE

–

dumpSmap

Dump SMAP JSR45 info to a file.

FALSE

–

enablePooling

Determines whether tag handler pooling is enabled.

TRUE

–

engineOptionsClass

Allows specifying the Options class used to configure Jasper. If not present, the default EmbeddedServletOptions will be used.

-

–

errorOnUseBeanInvalidClassAttribute

Should Jasper issue an error when the value of the class attribute in an useBean action is not a valid bean class

TRUE

–

fork

Only relevant if you use Ant to compile jsps: by default Jetty will use the Eclipse jdt compiler.

TRUE

-

genStrAsCharArray

Option for generating Strings as char arrays.

FALSE

–

ieClassId

The class-id value to be sent to Internet Explorer when using <jsp:plugin> tags.

clsid:8AD9C840-044E-11D1-B3E9-00805F499D93

–

javaEncoding

Pass through the encoding to use for the compilation.

UTF8

–

jspIdleTimeout

The amount of time in seconds a JSP can be idle before it is unloaded. A value of zero or less indicates never unload.

-1

–

keepgenerated

Do you want to keep the generated Java files around?

TRUE

–

mappedFile

Support for mapped Files. Generates a servlet that has a print statement per line of the JSP file 

TRUE

–

maxLoadedJsps

The maximum number of JSPs that will be loaded for a web application. If more than this number of JSPs are loaded, the least recently used JSPs will be unloaded so that the number of JSPs loaded at any one time does not exceed this limit. A value of zero or less indicates no limit.

-1

–

modificationTestInterval

If development=true, interval between recompilation checks, triggered by a request.

4

–

quoteAttributeEL

When EL is used in an attribute value on a JSP page, should the rules for quoting of attributes described in JSP.1.6 be applied to the expression

TRUE

-

recompileOnFail

If a JSP compilation fails should the modificationTestInterval be ignored and the next access trigger a re-compilation attempt? Used in development mode only and is disabled by default as compilation may be expensive and could lead to excessive resource usage.

FALSE

–

scratchDir

Directory where servlets are generated. The default is the value of the context attribute jakarta.servlet.context.tempdir, or the system property java.io.tmpdir if the context attribute is not set.

–

–

strictQuoteEscaping

Should the quote escaping required by section JSP.1.6 of the JSP specification be applied to scriplet expression.

TRUE

-

suppressSmap

Generation of SMAP info for JSR45 debugging.

FALSE

–

trimSpaces

Should template text that consists entirely of whitespace be removed from the output (true), replaced with a single space (single) or left unchanged (false)? Note that if a JSP page or tag file specifies a trimDirectiveWhitespaces value of true, that will take precedence over this configuration setting for that page/tag. trimmed?

FALSE

–

xpoweredBy

Generate an X-Powered-By response header.

FALSE

FALSE

Configuration

The JSP engine has many configuration parameters. Some parameters affect only precompilation, and some affect runtime recompilation checking. Parameters also differ among the various versions of the JSP engine. This page lists the configuration parameters, their meanings, and their default settings. Set all parameters on the org.eclipse.jetty.jsp.JettyJspServlet instance defined in the webdefault.xml file.

Be careful: for all of these parameters, if the value you set doesn’t take effect, try using all lower case instead of camel case, or capitalizing only some of the words in the name, as JSP is inconsistent in its parameter naming strategy.

Modifying Configuration

Overriding webdefault.xml

You can make a copy of the {$jetty.home}/etc/webdefault.xml that ships with Jetty, apply your changes, and use it instead of the shipped version. The example below shows how to do this when using the Jetty Maven plugin.

  <plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <configuration>
      <webApp>
        <defaultsDescriptor>src/main/resources/webdefault.xml</defaultsDescriptor>
      </webApp>
  </plugin>

If you are using the Jetty distribution, and you want to change the JSP settings for just one or a few of your webapps, copy the {$jetty.home}/etc/webdefault.xml file somewhere, modify it, and then use a context xml file to set this file as the defaultsDescriptor for your webapp. Here’s a snippet:

 <Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
   <Set name="contextPath">/foo</Set>
   <Set name="war"><Property name="jetty.home" default="."/>/webapps/foobar.war</Set>
   <Set name="defaultsDescriptor">/home/smith/dev/webdefault.xml</Set>
 </Configure>

If you want to change the JSP settings for all webapps, edit the {$jetty.home}/etc/webdefaults.xml file directly instead.

Configuring the JSP Servlet in web.xml

Another option is to add an entry for the JSPServlet to the WEB-INF/web.xml file of your webapp and change or add init-params. You may also add (but not remove) servlet-mappings. You can use the entry in {$jetty.home}/etc/webdefault.xml as a starting point.

 <servlet id="jsp">
     <servlet-name>jsp</servlet-name>
     <servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
     <init-param>
         <param-name>keepgenerated</param-name>
         <param-value>true</param-value>
     </init-param>
     ...

     <load-on-startup>0</load-on-startup>
   </servlet>

   <servlet-mapping>
     <servlet-name>jsp</servlet-name>
     <url-pattern>*.jsp</url-pattern>
     <url-pattern>*.jspf</url-pattern>
     <url-pattern>*.jspx</url-pattern>
     <url-pattern>*.xsp</url-pattern>
     <url-pattern>*.JSP</url-pattern>
     <url-pattern>*.JSPF</url-pattern>
     <url-pattern>*.JSPX</url-pattern>
     <url-pattern>*.XSP</url-pattern>
   </servlet-mapping>

   <servlet id="my-servlet">
     <servlet-name>myServlet</servlet-name>
     <servlet-class>com.acme.servlet.MyServlet</servlet-class>
      ...
Configuring Async Support

By default, Jetty does not enable async support for the JSP servlet. Configuring the JSP servlet for async is relatively easy - simply define the async-supported parameter as true in either your webdefault.xml or the web.xml for a specific context.

<servlet id="jsp">
  <servlet-name>jsp</servlet-name>
  <async-supported>true</async-supported>
</servlet>

Using JSTL Taglibs

The JavaServer Pages Standlard Tag Library (JSTL) is part of the Jetty distribution and is automatically put on the classpath when you select your flavour of JSP. It is also automatically on the classpath for the Jetty Maven plugin, which uses the Apache JSP engine.

Embedding

If you are using Jetty in an embedded scenario, and you need to use JSTL, then you must ensure that the JSTL jars are included on the container’s classpath - that is the classpath that is the parent of the webapp’s classpath. This is a restriction that arises from the JavaEE specification.

Glassfish JSTL

You will need to put the jars that are present in the {$jetty.home}/lib/glassfish-jstl directory onto the container’s classpath. The Apache JSP engine will find the JSTL tag definitions inside these jars during startup.

As an efficiency enhancement, you can have jetty examine the JSTL jars to find the tags, and pre-feed them into the Apache JSP engine. This is more efficient, because jetty will only scan the jars you tell it to, whereas the Apache JSP engine will scan every jar, which can be time-consuming in applications with a lot of jars on the container classpath.

To take advantage of this efficiency enhancement, set up the org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern to include a pattern that will match the names of the JSTL jars. The Embedded Examples section includes a worked code example of how to do this. Below is a snippet from the example:

  webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*/[^/]*taglibs.*\\.jar$");

Using JSF Taglibs

The following sections provide information about using JSF TagLibs with Jetty Standalone and the Jetty Maven Plugin.

Using JSF Taglibs with Jetty Distribution

If you want to use JSF with your webapp, you need to copy the JSF implementation Jar (whichever Jar contains the META-INF/*.tld files from your chosen JSF implementation) into Jetty’s shared container lib directory. You can either put them into the lib directory for Apache {$jetty.home}/lib/apache-jsp or put them into {$jetty.home}/lib/ext.

Using JSF Taglibs with Jetty Maven Plugin

You should make your JSF jars dependencies of the plugin and not the webapp itself. For example:

   <plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <configuration>
       <webApp>
         <contextPath>/${artifactId}</contextPath>
       </webApp>
    </configuration>
    <dependencies>
      <dependency>
        <groupId>com.sun.faces</groupId>
        <artifactId>jsf-api</artifactId>
        <version>2.0.8</version>
      </dependency>
      <dependency>
        <groupId>com.sun.faces</groupId>
        <artifactId>jsf-impl</artifactId>
        <version>2.0.8</version>
     </dependency>
    </dependencies>
  </plugin>

Platforms, Stacks and Alternative Distributions

Many many options…​

In addition to using Jetty in its distribution form and its multiple embedded forms, there are a number of alternative ways to use Jetty. Many products and open source projects out there distribute Jetty themselves, in both distribution and embedded forms, not to mention different operating systems bundling Jetty in other installable forms.

If your platform supports Jetty from a distribution or deployment perspective and want to be included on this list just fork the documentation and submit a pull request, or contact us. Check out our list of Powered By page for software that makes use of Jetty, often in novel and exciting ways.

Jelastic

Jelastic is a wonderful place to host your applications with solid support for Jetty. As a cloud hosting platform they take the majority of configuration and installation details out of the picture and focus on letting you focus on your web application.

CloudFoundry

This is an increasingly aged integration, things like likely changed enough this is not directly useful but may serve as a useful starting point should someone want to look into it.

Overview

CloudFoundry is an open platform intended as a place to deploy end user applications in a manner which is both simple and eminently scalable to fit the needs of the application. With the release of their V2 framework the Jetty project has created a buildpack which allows you to deploy your java based web application onto Jetty and still make use of the remainder of the CloudFoundry platform.

This buildpack itself is quite simple to use. A collection of ruby scripting and the buildpack conventions will allow Jetty to be downloaded, configured and customized to your needs and then have your web application deployed onto it. While the default buildpack we have created is useful to deploy a stock configuration of jetty, it is quite likely that you will want to fork the buildpack and tweak it to fit your immediate needs. This process is made trivial since buildpacks install from a github repository. For example, to change the jetty version simply fork it in GitHub and tweak the JETTY_VERSION string in the jetty_web.rb file.

If you have additional modifications to make to the Jetty server, like perhaps configuring additional static contexts, setting up a proxy servlet, adding jar files to the jetty home/lib/ext directory, etc you can either adapt the ruby scripting directly or place them under the appropriate location in the /resources directory of this buildpack and they will be copied into the correct location.

For the time being I’ll leave this buildpack under my personal github account and should there be interest expressed I am more then happy to push it over to https://github.com/jetty-project down the road for proper contributions, etc.

Usage

To show how incredibly easy it is to use the Jetty buildpack with cloudfoundry, this is all the more you need to do to deploy your application. Refer to the CloudFoundry documentation to get started, get the cf utilities installed and an environment configured.

$ cf push snifftest --buildpack=git://github.com/jmcc0nn3ll/jetty-buildpack.git
In this example the web application is uploaded from the current directory so make sure you have changed directory into the root of your web application. The snifftest on the commandline refers to what you are calling the application, not the directory to deploy. Also note that the webapplication is installed into the ROOT context of Jetty as is available at the root context of the server. Any additional web applications will have to be configured within the buildpack as mentioned above.

You will be prompted to answer a series of questions describing the execution environment and any additional services you need enabled (databases, etc).

Instances> 1

Custom startup command> none

1: 64M
2: 128M
3: 256M
4: 512M
5: 1G
Memory Limit> 256M

Creating snifftest... OK

1: snifftest
2: none
Subdomain> snifftest

1: a1-app.cf-app.com
2: none
Domain> a1-app.cf-app.com

Binding snifftest.a1-app.cf-app.com to snifftest... OK

Create services for application?> n

Save configuration?> n

Once answered you will see the installation process of your application.

Uploading snifftest... OK
Starting snifftest... OK
-> Downloaded app package (4.0K)
Initialized empty Git repository in /tmp/buildpacks/jetty-buildpack.git/.git/
Installing jetty-buildpack.git.
Downloading JDK...
Copying openjdk-1.7.0_21.tar.gz from the buildpack cache ...
Unpacking JDK to .jdk
Downloading Jetty: jetty-home-12.0.9-SNAPSHOT.tar.gz
Downloading jetty-home-12.0.9-SNAPSHOT.tar.gz from http://repo2.maven.org/maven2/org/eclipse/jetty/jetty-home/10.0.0.v202012xx/ ...
Unpacking Jetty to .jetty
-> Uploading staged droplet (36M)
-> Uploaded droplet
Checking snifftest...
Staging in progress...
Staging in progress...
Staging in progress...
Staging in progress...
Staging in progress...
Staging in progress...
  0/1 instances: 1 starting
  0/1 instances: 1 starting
  0/1 instances: 1 starting
  0/1 instances: 1 starting
  1/1 instances: 1 running
OK

The application is now available at the configured location! Under the url http://snifftest.a1-app.cf-app.com/ in this particular example.

Acknowledgements

The Jetty buildpack was forked from the CloudFoundry Java buildpack. The Virgo Buildpack that Glyn worked on was used as a sanity check.

CloudFoundry buildpacks were modelled on Heroku buildpacks.

Amazon Elastic Beanstalk

This is an increasingly aged integration, things like likely changed enough this is not directly useful but may serve as a useful starting point should someone want to look into it.

Elastic Beanstalk is a component with the Amazon Web Services offering that allows you to configure an entire virtual machine based on one of several available baseline configurations and then customize it through a powerful configuration system. While the default offerings currently available are based on Tomcat for for the java community, we worked out the basics using that configuration system to enable the usage of Jetty instead.

Overview

Elastic beanstalk has a very powerful configuration mechanism so this integration taps into that to effectively rework the tomcat configuration and replace it with the bits required to make jetty run in its place. Below is a walk through of what the various configuration files are doing and how the general flow of configuration on beanstalk happens.

There is an .ebextensions directory in your beanstalk application which contains all of the files requires to configure and customize your beanstalk and application combo. Files that end in .config in this directory are processed in alphabetical order.

00-java7.config

installs java 7 onto the beanstalk environment and makes it the default

10-tweak.config

not required, but changes the /opt/elasticbeanstalk directory to be readable making debugging easier

11-jetty.config

installs jetty9 into /opt/jetty-9 and removes unneeded distribution files

12-beanstalk.config

handles replacing tomcat with jetty in many configuration files, configures logging and wires up system startup processes. Some files in your .ebextensions directory are moved to replace files under /opt/elasticbeanstalk.

If you look in the .ebextensions directory of your application you should also see other jetty specific xml and ini files. The final config file handles these as they are largely customization for your application.

20-testapp.config

layers application specific configuration files into the jetty installation

The files in our example test webapp here enable various OPTIONS for libraries that need to be loaded, customize the root application being deployed and even deploy additional contexts like we do in our jetty distribution demo. This is also the mechanism that you would use to wire up application specific things, for example if you needed additional software installed, customized directories made, etc.

Maven Bits

Support for this feature leverages Maven to make things easy and is composed of three different modules.

jetty-beanstalk-overlay

This is the collection of scripts that are required to wedge jetty into the normal beanstalk setup. This module is intended to extract into an webapp to enable it for beanstalk usage with jetty.

jetty-beanstalk-resources

This generates an artifact of files that are downloaded by the configuration process and contains replacements for certain beanstalk files as well as various system level jetty configuration files like an updated jetty.sh script for the /etc/init.d setup.

jetty-beanstalk-testapp

An example webapp that shows both how to combine the war file from another maven module with the jetty-beanstalk-overlay to produce a beanstalk enabled application bundle. Also included is examples of how to alter the jetty configuration for things like a customized start.ini file.

The test webapps needs access to a snapshot version of the test-jetty-webapp so it really serves as more of an example of how to layer your webapp with the bits required to customize your app for beanstalk and jetty.

To actually make use of these artifacts you currently must clone this git repository and build it locally. Once you have the artifacts you simply need to copy the approach in the jetty-beanstalk-testapp to apply the configuration to your webapp.

Bluepill is used to manage the start and stop process of the app server. This seems to be a problematic bit of software with a colored history and the version in use at the time of this writing is old. When starting and stopping (or restarting) the appserver you may see error messages show up that the Server timed out getting a response or things like that. These are red herrings and my experience is that jetty has started and stopped just fine, the pid file required shows up in a very timely fashion (under /var/run/jetty.pid) so do check that the app server has started, but please be aware there is a strangeness here that hasn’t been sorted out yet.

Fedora

As of Fedora 19, Jetty 9 is the version of Jetty available. This distribution of Jetty is not created or maintained by the Jetty project though we have had a fair amount of communication with the folks behind it and we are very pleased with how this Linux distribution has stayed current. Releases are kept largely in sync with our releases as there is a wonderful automatic notification mechanism in place for Fedora that detects our releases and immediately opens an issue for them to update.

Ubuntu

Currently there are no actual .deb files available for installing on Debian based Linux machines but there is a handy blog that as been largely been kept up to date on the steps involved through the comments.

Jetty Runner

This chapter explains how to use the jetty-runner to run your webapps without needing an installation of Jetty.

Use Jetty Without an Installed Distribution

The idea of the jetty-runner is extremely simple – run a webapp directly from the command line using a single jar file and as much default configuration as possible. Of course, if your webapp is not as straightforward, the jetty-runner has command line options which allow you to customize the execution environment.

Preparation

You will need the jetty-runner jar:

  1. Download the jetty-runner jar available at Maven Central.

Deploying a Simple Context

Let’s assume we have a very simple webapp that does not need any resources from its environment, nor any configuration apart from the defaults. Starting it is as simple as performing the following:

> java -jar jetty-runner.jar simple.war

This will start Jetty on port 8080, and deploy the webapp to /.

Your webapp does not have to be packed into a war, you can deploy a webapp that is a directory instead in the same way:

> java -jar jetty-runner.jar simple

In fact, the webapp does not have to be a war or even a directory, it can simply be a Jetty context xml file that describes your webapp:

> java -jar jetty-runner.jar simple-context.xml
When using a context xml file, the application being deployed is not even required to be a fully-fledged webapp. It can simply be a Jetty context.

By default, jetty-runner implements all Configuration Classes so that users can set up and deploy new instances with as little configuration as possible. If you wish to only implement certain Configuration Classes, they will need to be defined in the context xml for the webapp/context. The default Configuration Classes are:

org.eclipse.jetty.ee9.webapp.WebInfConfiguration org.eclipse.jetty.ee9.webapp.WebXmlConfiguration org.eclipse.jetty.ee9.webapp.MetaInfConfiguration org.eclipse.jetty.ee9.webapp.FragmentConfiguration org.eclipse.jetty.ee9.webapp.JettyWebXmlConfiguration org.eclipse.jetty.plus.webapp.EnvConfiguration org.eclipse.jetty.plus.webapp.PlusConfiguration org.eclipse.jetty.annotations.AnnotationConfiguration

You can learn more about implementing specific Configuration Classes in the Jetty documentation.

Deploying Multiple Contexts

If you have more than one webapp that must be deployed, simply provide them all on the command line. You can control the context paths for them using the --path parameter. Here’s an example of deploying 2 wars (although either or both of them could be unpacked directories instead):

> java -jar jetty-runner.jar --path /one my1.war --path /two my2.war

If you have context xml files that describe your webapps, you can fully configure your webapps in them and hence you won’t need to use the command line switches. Just provide the list of context files like so:

> java -jar jetty-runner.jar my-first-context.xml my-second-context.xml my-third-context.xml
Switched used on the command line override configuration file settings. So, for example, you could set the context path for the webapp inside the context xml file, and use the --path switch to override it on the command line.
Changing the Default Port

By default the jetty-runner will listen on port 8080. You can easily change this on the command line using the --port command. Here’s an example that runs our simple.war on port 9090:

> java -jar jetty-runner.jar --port 9090 simple.war
Using jetty.xml Files

Instead of, or in addition to, using command line switches, you can use one or more jetty.xml files to configure the environment for your webapps. Here’s an example where we apply two different jetty.xml files:

> java -jar jetty-runner.jar --config jetty.xml --config jetty-https.xml simple.war

Full Configuration Reference

You can see the fill set of configuration options using the --help switch:

> java -jar jetty-runner.jar --help

Here’s what the output will look like:

Usage: java [-Djetty.home=dir] -jar jetty-runner.jar [--help|--version] [ server opts] [[ context opts] context ...]
Server opts:
 --version                           - display version and exit
 --log file                          - request log filename (with optional 'yyyy_mm_dd' wildcard
 --out file                          - info/warn/debug log filename (with optional 'yyyy_mm_dd' wildcard
 --host name|ip                      - interface to listen on (default is all interfaces)
 --port n                            - port to listen on (default 8080)
 --stop-port n                       - port to listen for stop command (or -DSTOP.PORT=n)
 --stop-key n                        - security string for stop command (required if --stop-port is present) (or -DSTOP.KEY=n)
 [--jar file]*n                      - each tuple specifies an extra jar to be added to the classloader
 [--lib dir]*n                       - each tuple specifies an extra directory of jars to be added to the classloader
 [--classes dir]*n                   - each tuple specifies an extra directory of classes to be added to the classloader
 --stats [unsecure|realm.properties] - enable stats gathering servlet context
 [--config file]*n                   - each tuple specifies the name of a jetty xml config file to apply (in the order defined)
Context opts:
 [[--path /path] context]*n          - WAR file, web app dir or context xml file, optionally with a context path
Printing the Version

Print out the version of Jetty and then exit immediately.

> java -jar jetty-runner.jar --version
Configuring a Request Log

Cause Jetty to write a request log with the given name. If the file is prefixed with yyyy_mm_dd then the file will be automatically rolled over. Note that for finer grained configuration of the request log, you will need to use a Jetty xml file instead.

> java -jar jetty-runner.jar --log yyyy_mm_dd-requests.log  my.war
Configuring the Output Log

Redirect the output of jetty logging to the named file. If the file is prefixed with yyyy_mm_dd then the file will be automatically rolled over.

> java -jar jetty-runner.jar --out yyyy_mm_dd-output.log my.war
Configuring the Interface for HTTP

Like Jetty standalone, the default is for the connectors to listen on all interfaces on a machine. You can control that by specifying the name or ip address of the particular interface you wish to use with the --host argument:

> java -jar jetty-runner.jar --host 192.168.22.19 my.war
Configuring the Port for HTTP

The default port number is 8080. To configure a https connector, use a Jetty xml config file instead.

> java -jar jetty-runner.jar --port 9090  my.war
Configuring Stop

You can configure a port number for Jetty to listen on for a stop command, so you are able to stop it from a different terminal. This requires the use of a "secret" key, to prevent malicious or accidental termination. Use the --stop-port and --stop-key (or -DSTOP.PORT= and -DSTOP.KEY=, respectively) parameters as arguments to the jetty-runner:

> java -jar jetty-runner.jar --stop-port 8181 --stop-key abc123

Then, to stop Jetty from a different terminal, you need to supply the same port and key information. For this you’ll either need a local installation of Jetty, the jetty-maven-plugin, the jetty-ant plugin, or a custom class. Here’s how to use a Jetty installation to perform a stop:

> java -jar start.jar -DSTOP.PORT=8181 -DSTOP.KEY=abc123 --stop
Configuring the Container Classpath

With a local installation of Jetty, you add jars and classes to the container’s classpath by putting them in the {$jetty.base}/lib directory. With the jetty-runner, you can use the --lib, --jar and --classes arguments instead to achieve the same thing.

--lib adds the location of a directory which contains jars to add to the container classpath. You can add 1 or more. Here’s an example of configuring 2 directories:

> java -jar jetty-runner.jar --lib /usr/local/external/lib --lib $HOME/external-other/lib my.war

--jar adds a single jar file to the container classpath. You can add 1 or more. Here’s an example of configuring 3 extra jars:

> java -jar jetty-runner.jar --jar /opt/stuff/jars/jar1.jar --jar $HOME/jars/jar2.jar --jar /usr/local/proj/jars/jar3.jar  my.war

--classes add the location of a directory containing classes to add to the container classpath. You can add 1 or more. Here’s an example of configuring a single extra classes dir:

> java -jar jetty-runner.jar --classes /opt/stuff/classes my.war
When using the --jar and/or --lib arguments, by default these will not be inspected for META-INF information such as META-INF/resources, META-INF/web-fragment.xml, or META-INF/taglib.tld. If you require these jar files inspected you will need to define the jar pattern in your context xml file. Jetty-Runner automatically provides and appends a suitable pattern for jtsl taglibs (this pattern is different than the one in the standard Jetty distribution).
Gathering Statistics

If statistics gathering is enabled, then they are viewable by surfing to the context /stats. You may optionally protect access to that context with a password. Here’s an example of enabling statistics, with no password protection:

> java -jar jetty-runner.jar --stats unsecure my.war

If we wished to protect access to the /stats context, we would provide the location of a Jetty realm configuration file containing authentication and authorization information. For example, we could use the following example realm file from the Jetty distribution:

jetty: MD5:164c88b302622e17050af52c89945d44,user
admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin
other: OBF:1xmk1w261u9r1w1c1xmq,user
plain: plain,user
user: password,user
# This entry is for digest auth.  The credential is a MD5 hash of username:realmname:password
digest: MD5:6e120743ad67abfbc385bc2bb754e297,user

Assuming we’ve copied it into the local directory, we would apply it like so

> java -jar jetty-runner.jar --stats realm.properties my.war

After navigating to http://localhost:8080/ a few times, we can point to the stats servlet on http://localhost:8080/stats to see the output:

Statistics:
Statistics gathering started 1490627ms ago

Requests:
Total requests: 9
Active requests: 1
Max active requests: 1
Total requests time: 63
Mean request time: 7.875
Max request time: 26
Request time standard deviation: 8.349764752888037


Dispatches:
Total dispatched: 9
Active dispatched: 1
Max active dispatched: 1
Total dispatched time: 63
Mean dispatched time: 7.875
Max dispatched time: 26
Dispatched time standard deviation: 8.349764752888037
Total requests suspended: 0
Total requests expired: 0
Total requests resumed: 0


Responses:
1xx responses: 0
2xx responses: 7
3xx responses: 1
4xx responses: 0
5xx responses: 0
Bytes sent total: 1453


Connections:
org.eclipse.jetty.server.ServerConnector@203822411
Protocols:http/1.1
Statistics gathering started 1490606ms ago
Total connections: 7
Current connections open: 1
Max concurrent connections open: 2
Total connections duration: 72883
Mean connection duration: 12147.166666666666
Max connection duration: 65591
Connection duration standard deviation: 23912.40292977684
Total messages in: 7
Total messages out: 7


Memory:
Heap memory usage: 49194840 bytes
Non-heap memory usage: 12611696 bytes

Configuring Security

Authentication and Authorization

There are two aspects to securing a web application(or context) within the Jetty server:

Authentication

The web application can be configured with a mechanism to determine the identity of the user. This is configured by a mix of standard declarations and jetty specific mechanisms and is covered in this section.

Authorization

Once the identify of the user is known (or not known), the web application can be configured via standard descriptors with security constraints that declare what resources that user may access.

Configuring an Authentication mechanism

Jetty server supports several standard authentication mechanisms: BASIC; DIGEST; FORM; CLIENT-CERT; and other mechanisms can be plugged in using the extensible JakartaAuthentication or SPNEGO mechanisms.

Internally, configuring an authentication mechanism is done by setting an instance of a the Authenticator interface onto the SecurityHandler of the context, but in most cases it is done by declaring a <login-config> element in the standard web.xml descriptor or via annotations.

Below is an example taken from the jetty-test-webapp web.xml that configures BASIC authentication:

  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Test Realm</realm-name>
  </login-config>

The jetty-test-webapp web.xml also includes commented out examples of other DIGEST and FORM configuration:

  <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>Test Realm</realm-name>
    <form-login-config>
       <form-login-page>/logon.html?param=test</form-login-page>
       <form-error-page>/logonError.html?param=test</form-error-page>
    </form-login-config>
  </login-config>

With FORM Authentication, you must also configure URLs of pages to generate a login form and handle errors. Below is a simple HTML form from the test webapp logon.html:

<HTML>
<H1>FORM Authentication demo</H1>
<form method="POST" action="j_security_check">
<table border="0" cellspacing="2" cellpadding="1">
<tr>
  <td>Username:</td>
  <td><input size="12" value="" name="j_username" maxlength="25" type="text"></td>
</tr>
<tr>
  <td>Password:</td>
  <td><input size="12" value="" name="j_password" maxlength="25" type="password"></td>
</tr>
<tr>
  <td colspan="2" align="center">
    <input name="submit" type="submit" value="Login">
  </td>
</tr>
</table>
</form>
</HTML>

The Authentication mechanism declared for a context / web application defines how the server obtain authentication credentials from the client, but it does not define how the server checks if those credentials are valid. To check credentials, the server and/or context also need to be configured with a LoginService instance, which may be matched by the declared realm-name.

Security Realms

Security realms allow you to secure your web applications against unauthorized access. Protection is based on authentication that identifies who is requesting access to the webapp and access control that restricts what can be accessed and how it is accessed within the webapp.

A webapp statically declares its security requirements in its web.xml file. Authentication is controlled by the <login-config> element. Access controls are specified by <security-constraint> and <security-role-ref> elements. When a request is received for a protected resource, the web container checks if the user performing the request is authenticated, and if the user has a role assignment that permits access to the requested resource.

The Servlet Specification does not address how the static security information in the WEB-INF/web.xml file is mapped to the runtime environment of the container. For Jetty, the LoginService performs this function.

A LoginService has a unique name, and gives access to information about a set of users. Each user has authentication information (e.g. a password) and a set of roles associated with him/herself.

You may configure one or many different LoginServices depending on your needs. A single realm would indicate that you wish to share common security information across all of your web applications. Distinct realms allow you to partition your security information webapp by webapp.

When a request to a web application requires authentication or authorization, Jetty will use the <realm-name> sub-element inside <login-config> element in the web.xml file to perform an exact match to a LoginService.

Scoping Security Realms

A LoginService has a unique name, and is composed of a set of users. Each user has authentication information (for example, a password) and a set of roles associated with him/herself. You can configure one or many different realms depending on your needs.

  • Configure a single LoginService to share common security information across all of your web applications.

  • Configure distinct LoginServices to partition your security information webapp by webapp.

Globally Scoped

A LoginService is available to all web applications on a Server instance if you add it as a bean to the Server. Such a definition would go into an xml file in your ${jetty.base}/etc directory, e.g. ${jetty.base}/etc/my-realm.xml and you would add this xml file to the execution path via start.ini or start.d (you may want to review the material in the Starting Jetty chapter). Here’s an example of an xml file that defines an in-memory type of LoginService called the HashLoginService:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  <Call name="addBean">
    <Arg>
      <New class="org.eclipse.jetty.security.HashLoginService">
        <Set name="name">Test Realm</Set>
        <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
        <Set name="hotReload">true</Set>
      </New>
    </Arg>
  </Call>
</Configure>

If you define more than one LoginService on a Server, you will need to specify which one you want used for each context. You can do that by telling the context the name of the LoginService, or passing it the LoginService instance. Here’s an example of doing both of these, using a context xml file:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
 <Get name="securityHandler">
   <!-- Either: -->
   <Set name="loginService">
     <New class="org.eclipse.jetty.security.HashLoginService">
           <Set name="name">Test Realm</Set>
     </New>
   </Set>

   <!-- or if you defined a LoginService called "Test Realm" in jetty.xml : -->
   <Set name="realmName">Test Realm</Set>

 </Get>
Per-Webapp Scoped

Alternatively, you can define a LoginService for just a single web application. Here’s how to define the same HashLoginService, but inside a context xml file:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/test</Set>
  <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test</Set>
  <Get name="securityHandler">
    <Set name="loginService">
      <New class="org.eclipse.jetty.security.HashLoginService">
            <Set name="name">Test Realm</Set>
            <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
      </New>
    </Set>
  </Get>
</Configure>

Jetty provides a number of different LoginService types which can be seen in the next section.

Configuring a LoginService

A LoginService instance is required by each context/webapp that has a authentication mechanism, which is used to check the validity of the username and credentials collected by the authentication mechanism. Jetty provides the following implementations of LoginService:

HashLoginService

A user realm that is backed by a hash map that is filled either programatically or from a Java properties file.

JDBCLoginService

Uses a JDBC connection to an SQL database for authentication

DataSourceLoginService

Uses a JNDI defined DataSource for authentication

JAASLoginService

Uses a JAAS provider for authentication; see the section on JAAS support for more information

SpnegoLoginService

SPNEGO Authentication; see the section on SPNEGO support for more information.

An instance of a LoginService can be matched to a context/webapp by:

  • A LoginService instance may be set directly on the SecurityHandler instance via embedded code or IoC XML

  • Matching the realm-name defined in web.xml with the name of a LoginService instance that has been added to the Server instance as a dependent bean

  • If only a single LoginService instance has been set on the Server then it is used as the login service for the context

HashLoginService

The HashLoginService is a simple and efficient login service that loads usernames, credentials and roles from a Java properties file in the format:

username: password[,rolename ...]

Where:

username

is the user’s unique identity

password

is the user’s (possibly obfuscated or MD5 encrypted) password;

rolename

is a role of the user

For example:

admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin
other: OBF:1xmk1w261u9r1w1c1xmq
guest: guest,read-only

You configure the HashLoginService with a name and a reference to the location of the properties file:

<Item>
<New class="org.eclipse.jetty.security.HashLoginService">
  <Set name="name">Test Realm</Set>
  <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
</New>
</Item>

You can also configure it to reload the configuration file when changes to it are detected.

<New class="org.eclipse.jetty.security.HashLoginService">
    <Set name="name">Test Realm</Set>
    <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
    <Set name="hotReload">true</Set>
    <Call name="start"></Call>
  </New>
JDBCLoginService

In this implementation, authentication and role information is stored in a database accessed via JDBC. A properties file defines the JDBC connection and database table information. Here is an example of a properties file for this realm implementation:

jdbcdriver = org.gjt.mm.mysql.Driver
url = jdbc:mysql://localhost/jetty
username = jetty
password = jetty
usertable = users
usertablekey = id
usertableuserfield = username
usertablepasswordfield = pwd
roletable = roles
roletablekey = id
roletablerolefield = role
userroletable = user_roles
userroletableuserkey = user_id
userroletablerolekey = role_id
cachetime = 300

The format of the database tables is (pseudo-sql):

users
(
  id integer PRIMARY KEY,
  username varchar(100) NOT NULL UNIQUE KEY,
  pwd varchar(50) NOT NULL
);
user_roles
(
  user_id integer NOT NULL,
  role_id integer NOT NULL,
  UNIQUE KEY (user_id, role_id),
  INDEX(user_id)
);
roles
(
  id integer PRIMARY KEY,
  role varchar(100) NOT NULL UNIQUE KEY
);

Where:

  • users is a table containing one entry for every user consisting of:

    id

    the unique identity of a user

    user

    the name of the user

    pwd

    the user’s password (possibly obfuscated or MD5 encrypted)

  • user-roles is a table containing one row for every role granted to a user:

    user_id

    the unique identity of the user

    role_id

    the role for a user

  • roles is a a table containing one role for every role in the system:

    id

    the unique identifier of a role

    role

    a human-readable name for a role

If you want to use obfuscated, MD5 hashed or encrypted passwords the pwd column of the users table must be large enough to hold the obfuscated, hashed or encrypted password text plus the appropriate prefix.

You define a JDBCLoginService with the name of the realm and the location of the properties file describing the database:

<New class="org.eclipse.jetty.security.JDBCLoginService">
  <Set name="name">Test JDBC Realm</Set>
  <Set name="config">etc/jdbcRealm.properties</Set>
</New>

Authorization

As far as the Servlet Specification is concerned, authorization is based on roles. As we have seen, a LoginService associates a user with a set of roles. When a user requests a resource that is access protected, the LoginService will be asked to authenticate the user if they are not already, and then asked to confirm if that user possesses one of the roles permitted access to the resource.

Until Servlet 3.1, role-based authorization could define:

  • Access granted to a set of named roles:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Admin Data</web-resource-name>
    <url-pattern>/foo/admin/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>admin</role-name>
    <role-name>manager</role-name>
  </auth-constraint>
</security-constraint>
  • Access totally forbidden, regardless of role:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Protected Data</web-resource-name>
    <url-pattern>/foo/protected/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
  </auth-constraint>
</security-constraint>
  • Access granted to a user in any of the roles defined in the effective web.xml. This is indicated by the special value of * for the <role-name> of a <auth-constraint> in the <security-constraint>:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Role Data</web-resource-name>
    <url-pattern>/foo/role/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>*</role-name>
  </auth-constraint>
</security-constraint>

Servlet 3.1 introduced an additional authorization:

  • Access granted to any user who is authenticated, regardless of roles. This is indicated by the special value of ** for the <role-name> of a <auth-constraint> in the <security-constraint>:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Authenticated Data</web-resource-name>
    <url-pattern>/foo/authenticated/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>**</role-name>
  </auth-constraint>
</security-constraint>

Additionally, when configuring your security constraints you can protect various HTTP methods as well, such as PUT, GET, POST, HEAD or DELETE. This is done by adding the method you want to protect as a <http-method> in the <web-resource-collection>. You can then define roles that should be able to perform these protected methods in an <auth-constraint>:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Authenticated Data</web-resource-name>
    <url-pattern>/foo/authenticated/*</url-pattern>
    <http-method>DELETE</http-method>
    <http-method>POST</http-method>
  </web-resource-collection>
  <auth-constraint>
    <role-name>admin</role-name>
  </auth-constraint>
</security-constraint>

In the above example, only users with an admin role will be able to perform DELETE or POST methods.

Configuring Authorization with Context XML Files

While the examples above show configuration of Authorization in a web.xml file, they can also be configured as part of the link#context xml file for a web application. This is especially helpful if authorization needs change over time and need updated without re-packaging the whole web app.

To do this, we add a section for security constraints into the context xml file for our web app as part of the securityHandler. In the example below, a HashLoginService is defined with authorization being granted too foo/* paths to users with the admin and manager roles.

<Configure id="testWebapp" class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Get name="securityHandler">
    <Set name="realmName">Test Realm</Set>
    <Set name="authMethod">BASIC</Set>
    <Call name="addConstraintMapping">
      <Arg>
         <New class="org.eclipse.jetty.security.ConstraintMapping">
            <Set name="pathSpec">/foo/*</Set>
            <Set name="constraint">
              <New class="org.eclipse.jetty.util.security.Constraint">
                  <Set name="name">Foo Auth</Set>
                  <Set name="authenticate">true</Set>
                  <Set name="roles">
                    <Array type="java.lang.String">
                      <Item>admin</Item>
                      <Item>manager</Item>
                    </Array>
                  </Set>
              </New>
            </Set>
         </New>
      </Arg>
    </Call>
    <Set name="loginService">
      <New class="org.eclipse.jetty.security.HashLoginService">
        <Set name="name">Test Realm</Set>
        <Set name="config">/src/tmp/small-security-test/realm.properties</Set>
      </New>
    </Set>
  </Get>
</Configure>

If roles changed in the future, administrators could easily change this context xml file without having to edit the contents of the web app at all.

Authentication and Authorization with Embedded Jetty

In addition to the distribution, security can be defined as part of an embedded implementation as well. Below is an example which, like the one above, sets up a server with a HashLoginService and adds security constraints to restrict access based on roles.

Unresolved directive in security/authentication.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../examples/embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java[]

Jakarta Authentication (JASPI)

Jetty can utilize portable authentication modules that implements the Jakara Authentication specification. This requires the jetty-jaspi module.

Only modules conforming to the ServerAuthModule interface in the JakartaAuthentication are supported. These modules must be configured before start-up.

The following illustrates a jetty module setting up HTTP Basic Authentication using a Jakarta Authentication module that comes packaged with the jetty-jaspi module: org.eclipse.jetty.security.jaspi.modules.BasicAuthenticationAuthModule

Unresolved directive in security/authentication.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../jetty-jaspi/src/main/config/etc/jaspi/jaspi-demo.xml[tags=documentation]

Given the portability goal of Jakarta Authentication, custom or 3rd party ServerAuthModule implementations may be configured instead here.

Limiting Form Content

Form content sent to the server is processed by Jetty into a map of parameters to be used by the web application. This can be vulnerable to denial of service (DOS) attacks since significant memory and CPU can be consumed if a malicious clients sends very large form content or large number of form keys. Thus Jetty limits the amount of data and keys that can be in a form posted to Jetty.

The default maximum size Jetty permits is 200000 bytes and 1000 keys. You can change this default for a particular webapp or for all webapps on a particular Server instance.

Configuring Form Limits for a Webapp

To configure the form limits for a single web application, the context handler (or webappContext) instance must be configured using the following methods:

ContextHandler.setMaxFormContentSize(int maxSizeInBytes);
ContextHandler.setMaxFormKeys(int formKeys);

These methods may be called directly when embedding Jetty, but more commonly are configured from a context XML file or WEB-INF/jetty-web.xml file:

<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">

  ...

  <Set name="maxFormContentSize">200000</Set>
  <Set name="maxFormKeys">200</Set>
</Configure>

Configuring Form Limits for the Server

If a context does not have specific form limits configured, then the server attributes are inspected to see if a server wide limit has been set on the size or keys. The following XML shows how these attributes can be set in jetty.xml:

<configure class="org.eclipse.jetty.server.Server">

  ...

  <Call name="setAttribute">
    <Arg>org.eclipse.jetty.server.Request.maxFormContentSize</Arg>
    <Arg>100000</Arg>
   </Call>
  <Call name="setAttribute">
    <Arg>org.eclipse.jetty.server.Request.maxFormKeys</Arg>
    <Arg>2000</Arg>
   </Call>
</configure>

Aliased Files and Symbolic links

Web applications will often serve static content from the file system provided by the operating system running underneath the JVM. However, because file systems often implement multiple aliased names for the same file, then security constraints and other servlet URI space mappings may inadvertently be bypassed by aliases.

A key example of this is case insensitivity and 8.3 filenames implemented by the Windows file system. If a file within a web application called /mysecretfile.txt is protected by a security constraint on the URI /mysecretfile.txt, then a request to /MySecretFile.TXT will not match the URI constraint because URIs are case sensitive, but the Windows file system will report that a file does exist at that name and it will be served despite the security constraint. Less well known than case insensitivity is that Windows files systems also support 8.3 filenames for compatibility with legacy programs. Thus a request to a URI like /MYSECR~1.TXT will again not match the security constraint, but will be reported as an existing file by the file system and served.

There are many examples of aliases, not just on Windows:

  • NTFS Alternate stream names like c:\test\file.txt::$DATA:name

  • OpenVMS support file versionig so that /mysecret.txt;N refers to version N of /mysecret.txt and is essentially an alias.

  • The clearcase software configuration management system provides a file system where @@ in a file name is an alias to a specific version.

  • The Unix files system supports /./foo.txt as and alias for /foo.txt

  • Many JVM implementations incorrectly assume the null character is a string terminator, so that a file name resulting from /foobar.txt%00 is an alias for /foobar.txt

  • Unix symbolic links and hard links are a form of aliases that allow the same file or directory to have multiple names.

In addition, it is not just URI security constraints that can be bypassed. For example the mapping of the URI pattern *.jsp to the JSP Servlet may be bypassed by an a request to an alias like /foobar.jsp%00, thus rather than execute the JSP, the source code of the JSP is returned by the file system.

Good Security Practise

Part of the problem with aliases is that the standard web application security model is to allow all requests except the ones that are specifically denied by security constraints. A best practice for security is to deny all requests and to permit only those that are specifically identified as allowable. While it is possible to design web application security constraints in this style, it can be difficult in all circumstances and it is not the default. T hus it is important for Jetty to be able to detect and deny requests to aliased static content.

Alias detection

It is impossible for Jetty to know of all the aliases that may be implemented by the file system running beneath it, thus it does not attempt to make any specific checks for any know aliases. Instead Jetty detects aliases by using the canonical path of a file. If a file resource handled by jetty has a canonical name that differs from the name used to request the resource, then Jetty determines that the resource is an aliased request and it will not be returned by the ServletContext.getResource(String) method (or similar) and thus will not be served as static content nor used as the basis of a JSP.

This if Jetty is running on a Windows operating system, then a file called /MySecret.TXT will have a canonical name that exactly matches that case. So while a request to /mysecret.txt or /MYSECR~1.TXT will result in a File Resource that matches the file, the different canonical name will indicate that those requests are aliases and they will not be served as static content and instead a 404 response returned.

Unfortunately this approach denies all aliases, including symbolic links, which can be useful in assembling complex web applications.

Serving Aliases and Symbolic Links

Not all aliases are bad nor should be seen as attempts to subvert security constraints. Specifically, symbolic links can be very useful when assembling complex web applications. As such, Jetty contexts support an extensible AliasCheck mechanism to allow aliases resources to be inspected and conditionally served. In this way, "good" aliases can be detected and served. Jetty provides several utility implementations of the AliasCheck interface as nested classes with ContextHandler:

ApproveAliases

Approve all aliases (Use with caution!).

AllowSymLinkAliasChecker

Approve Aliases using the java-7 Files.readSymbolicLink(path) and Path.toRealPath(…​) APIs to check that aliases are valid symbolic links.

By default, Jetty serves aliased files for implementations running on UNIX as Contexts are created with both the AllowSymLinkAliasChecker and ApproveNonExistentDirectoryAliases alias checkers.

An application is free to implement its own Alias checking. Alias Checkers can be installed in a context via the following XML used in a context deployer file or WEB-INF/jetty-web.xml:

  <!-- Allow symbolic links  -->
  <Call name="addAliasCheck">
    <Arg><New class="org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker"/></Arg>
  </Call>

Unresolved directive in security/chapter.adoc - include::secure-passwords.adoc[]

Setting Port 80 Access for a Non-Root User

On Unix-based systems, port 80 is protected; typically only the superuser root can open it. For security reasons, it is not desirable to run the server as root. This page presents several options to access port 80 as a non-root user, including using ipchains, iptables, Jetty’s SetUID feature, xinetd, and the Solaris 10 User Rights Management Framework.

Using ipchains

On some Linux systems you can use the ipchains REDIRECT mechanism to redirect from one port to another inside the kernel (if ipchains is not available, then iptables usually is):

# /sbin/ipchains -I input --proto TCP --dport 80 -j REDIRECT 8080

This command instructs the system as follows: "Insert into the kernel’s packet filtering the following as the first rule to check on incoming packets: if the protocol is TCP and the destination port is 80, redirect the packet to port 8080". Be aware that your kernel must be compiled with support for ipchains (virtually all stock kernels are). You must also have the ipchains command-line utility installed. You can run this command at any time, preferably just once, since it inserts another copy of the rule every time you run it.

Using iptables

On many Linux systems you can use the iptables REDIRECT mechanism to redirect from one port to another inside the kernel (if iptables is not available, then usually ipchains is).

You need to add something like the following to the startup scripts or your firewall rules:

# /sbin/iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

The underlying model of iptables is different from ipchains, so the forwarding normally happens only to packets originating outside of the server itself. You also need to allow incoming packets to port 8080 if you use iptables as a local firewall.

Be careful to place rules like this one early in your input chain. Such rules must precede any rule that accepts the packet, otherwise the redirection won’t occur. You can insert as many rules as required if your server needs to listen on multiple ports, as for HTTPS.

Configuring Jetty’s SetUID Feature

SetUID is a technique that uses Unix-like file system access rights to allow users to run an executable that would otherwise require higher privileges.

Jetty’s SetUID module allows you to run Jetty as a normal user even when you need to run Jetty on port 80 or 443.

To use it with the Jetty distribution:

  1. Ensure that you have the http.mod (and https.mod if you are using SSL) modules enabled for the base you are using. The http.mod is enabled by default in the distribution, while the https.mod is only enabled in the demo-base directory.

  2. Ensure that you have changed the http port to 80 (and changed the https port to 443 if you are using SSL).

  3. Enable the setuid.mod module:

    # java -jar start.jar --add-to-start=setuid
    The --add-to-start command will enable the setuid module for this and all subsequent executions of jetty. There are other ways to enable the module, such as for a single execution. For more information on the alternatives see the section on Managing Startup Modules.
  4. Edit the configuration for the setuid module to substitute the userid and groupid of the user to switch to after starting. If your server instance has a ${jetty.base/start.d} directory, this configuration is in the start.d/setuid.ini file instead. Otherwise. this configuration is in the ${jetty.base}start.ini file.

    Below are the lines to configure:
    jetty.startServerAsPrivileged=false
    jetty.username=foo
    jetty.groupname=bar
    jetty.umask=002
    As well as opening the connectors as root, you can also have Jetty start the Server as root before changing to the non-root user.
  5. A native code library is required to perform user switching. This code is hosted as part of the Jetty ToolChain project and is released independently from Jetty itself. You can find the source code in the eclipse/jetty.toolchain/jetty-setuid project. Build it locally, which will produce a native library appropriate for the operating system:

    # mvn clean install

    If you built on a linux machine you will find the native library in jetty-setuid/libsetuid-linux/target/libsetuid-linux.so. If you built on a different operating system you will find the library in a different subdirectory, with the name containing the name of the operating system. You may want copy this file into your Jetty distribution’s lib directory.

  6. Start Jetty as the root user in your base directory, providing the location of the native library to Java. Below is an example of how to do it from the command line, assuming you are in the demo-base directory:

    # sudo java -Djava.library.path=libsetuid-linux -jar $JETTY_HOME/start.jar

Using the Solaris 10 User Rights Management Framework

Solaris 10 provides a User Rights Management framework that can permit users and processes superuser-like abilities:

usermod -K defaultpriv=basic,net_privaddr myself

Now the myself user can bind to port 80.

Refer to the Solaris 10 and Solaris 11 Security Services documentation for more information.

JAAS Support

JAAS implements a Java version of the standard Pluggable Authentication Module (PAM) framework.

JAAS can be used for two purposes:

  • for authentication of users, to reliably and securely determine who is currently executing Java code, regardless of whether the code is running as an application, an applet, a bean, or a servlet

  • for authorization of users to ensure they have the access control rights (permissions) required to do the actions performed

JAAS authentication is performed in a pluggable fashion. This permits applications to remain independent from underlying authentication technologies. New or updated authentication technologies can be plugged under an application without requiring modifications to the application itself. Applications enable the authentication process by instantiating a LoginContext object, which in turn references a configuration to determine the authentication technology(ies), or LoginModule(s), to be used in performing the authentication. Typical LoginModules may prompt for and verify a username and password. Others may read and verify a voice or fingerprint sample.

See Java Authentication and Authorization Service (JAAS) Reference Guide for more information about JAAS.

Jetty and JAAS

Many application servers support JAAS as a means of bringing greater flexibility to the declarative security models of the J2EE (now known as the JavaEE) specification. Jetty support for JAAS provides greater alternatives for servlet security, and increases the portability of web applications.

The JAAS support aims to dictate as little as possible whilst providing a sufficiently flexible infrastructure to allow users to drop in their own custom LoginModules.

Configuration

Using JAAS with Jetty is very simply a matter of declaring a org.eclipse.jetty.jaas.JAASLoginService, creating a JAAS login module configuration file and specifying it on the Jetty run line. Let’s look at an example.

Step 1

Configure a Jetty org.eclipse.jetty.jaas.JAASLoginService to match the <realm-name> in your web.xml file. For example, if the web.xml contains a realm called "Test JAAS Realm" like so:

<login-config>
  <auth-method>FORM</auth-method>
  <realm-name>Test JAAS Realm</realm-name>
  <form-login-config>
    <form-login-page>/login/login</form-login-page>
    <form-error-page>/login/error</form-error-page>
  </form-login-config>
</login-config>

then you need to create a JAASLoginService with the matching realm name of "Test JAAS Realm":

<New class="org.eclipse.jetty.jaas.JAASLoginService">
  <Set name="Name">Test JAAS Realm</Set>
  <Set name="LoginModuleName">xyz</Set>
</New>

The LoginModuleName must match the name of your LoginModule as declared in your login module configuration file (see Step 2).

The name of the realm-name that you declare in web.xml must match exactly the Name field of your JAASLoginService.

You can declare your JAASLoginService in a couple of different ways:

  1. If you have more than one webapp that you would like to use the same security infrastructure, then you can declare your JAASLoginService in a top-level Jetty xml file as a bean that is added to the org.eclipse.jetty.server.Server. An example:

    <Configure id="Server" class="org.eclipse.jetty.server.Server">
    
      <Call name="addBean">
        <Arg>
          <New class="org.eclipse.jetty.jaas.JAASLoginService">
            <Set name="name">Test JAAS Realm</Set>
            <Set name="LoginModuleName">xyz</Set>
          </New>
        </Arg>
      </Call>
    
    </Configure>
  2. Alternatively, you can use a JAASLoginService with just a specific webapp by creating a context xml file for the webapp, and specifying the JAASLoginService in it:

    <Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
    
      <Set name="securityHandler">
        <New class="org.eclipse.jetty.security.ConstraintSecurityHandler">
         <Set name="loginService">
           <New class="org.eclipse.jetty.jaas.JAASLoginService">
             <Set name="name">Test JAAS Realm</Set>
             <Set name="loginModuleName">xyz</Set>
           </New>
         </Set>
        </New>
      </Set>
    
    </Configure>
Step 2

Set up your LoginModule in a configuration file, following the syntax rules :

xyz {
       com.acme.SomeLoginModule required debug=true;
    };
It is imperative that the application name on the first line is exactly the same as the LoginModuleName of your JAASLoginService.

You may find it convenient to name this configuration file as etc/login.conf because, as we will see below, some of the wiring up for JAAS has been done for you.

Step 3

You now need to invoke Jetty with support for JAAS. There are 2 aspects to this:

  • adding JAAS-related jars to the Jetty container classpath

  • setting the System property java.security.auth.login.config

To accomplish the above, use the Jetty startup modules mechanism to add the JAAS module:

java -jar start.jar --add-to-start=jaas
The top level of the distribution does not have the JAAS module enabled by default. However, there are several demo webapps - including a JAAS webapp - available in the demo-base directory of the distribution which has pre-enabled the JAAS module.

Now you will have a file named start.d/jaas.ini, which contains:

--module=jaas
jaas.login.conf=etc/login.conf

The jaas.login.conf property refers to the location of your LoginModule configuration file that you established in Step 2. If you called it etc/login.conf, then your work is done. Otherwise, change the value of the jaas.login.conf property to be the location of your LoginModule configuration file. Jetty will automatically use this property to set the value of the System property java.security.auth.login.config.

A Closer Look at JAASLoginService

To allow the greatest degree of flexibility in using JAAS with web applications, the JAASLoginService supports a couple of configuration options. Note that you don’t ordinarily need to set these explicitly, as Jetty has defaults which will work in 99% of cases. However, should you need to, you can configure:

  • a CallbackHandler (Default: org.eclipse.jetty.security.jaas.callback.DefaultCallbackHandler)

  • a list of classnames for the Principal implementation that equate to a user role (Default: org.eclipse.jetty.jaas.JAASRole)

Here’s an example of setting each of these (to their default values):

<New class="org.eclipse.jetty.jaas.JAASLoginService">
  <Set name="Name">Test JAAS Realm</Set>
  <Set name="LoginModuleName">xyz</Set>
  <Set name="CallbackHandlerClass">
       org.eclipse.jetty.security.jaas.callback.DefaultCallbackHandler
  </Set>
  <Set name="roleClassNames">
    <Array type="java.lang.String">
      <Item>org.eclipse.jetty.jaas.JAASRole</Item>
    </Array>
  </Set>
</New>
CallbackHandler

A CallbackHandler is responsible for interfacing with the user to obtain usernames and credentials to be authenticated.

Jetty ships with the org.eclipse.jetty.jaas.DefaultCallbackHandler which interfaces the information contained in the request to the Callbacks that are requested by LoginModules. You can replace this default with your own implementation if you have specific requirements not covered by the default.

Role Principal Implementation Class

When LoginModules authenticate a user, they usually also gather all of the roles that a user has and place them inside the JAAS Subject. As LoginModules are free to use their own implementation of the JAAS Principal to put into the Subject, Jetty needs to know which Principals represent the user and which represent his/her roles when performing authorization checks on <security-constraint>. The example LoginModules that ship with Jetty all use the org.eclipse.jetty.jaas.JAASRole class. However, if you have plugged in other LoginModules, you must configure the classnames of their role Principal implementations.

Sample LoginModules
Passwords can be stored in clear text, obfuscated or checksummed. The class org.eclipse.jetty.util.security.Password should be used to generate all varieties of passwords,the output from which can be put in to property files or entered into database tables. See more on this under the Configuration section on securing passwords.
JDBCLoginModule

The JDBCLoginModule stores user passwords and roles in a database that are accessed via JDBC calls. You can configure the JDBC connection information, as well as the names of the table and columns storing the username and credential, and the names of the table and columns storing the roles.

Here is an example login module configuration file entry for it using an HSQLDB driver:

jdbc {
      org.eclipse.jetty.jaas.spi.JDBCLoginModule required
      debug="true"
      dbUrl="jdbc:hsqldb:."
      dbUserName="sa"
      dbDriver="org.hsqldb.jdbcDriver"
      userTable="myusers"
      userField="myuser"
      credentialField="mypassword"
      userRoleTable="myuserroles"
      userRoleUserField="myuser"
      userRoleRoleField="myrole";
      };

There is no particular schema required for the database tables storing the authentication and role information. The properties userTable, userField, credentialField, userRoleTable, userRoleUserField, userRoleRoleField configure the names of the tables and the columns within them that are used to format the following queries:

  select <credentialField> from <userTable>
          where <userField> =?
  select <userRoleRoleField> from <userRoleTable>
          where <userRoleUserField> =?

Credential and role information is lazily read from the database when a previously unauthenticated user requests authentication. Note that this information is only cached for the length of the authenticated session. When the user logs out or the session expires, the information is flushed from memory.

Note that passwords can be stored in the database in plain text or encoded formats - see the note on "Passwords/Credentials" above.

DataSourceLoginModule

Similar to the JDBCLoginModule, but this LoginModule uses a DataSource to connect to the database instead of a JDBC driver. The DataSource is obtained by performing a JNDI lookup on java:comp/env/${dnJNDIName}.

A sample login module configuration using this method:

ds {
     org.eclipse.jetty.jaas.spi.DataSourceLoginModule required
     debug="true"
     dbJNDIName="ds"
     userTable="myusers"
     userField="myuser"
     credentialField="mypassword"
     userRoleTable="myuserroles"
     userRoleUserField="myuser"
     userRoleRoleField="myrole";
    };
PropertyFileLoginModule

With this login module implementation, the authentication and role information is read from a property file.

props {
        org.eclipse.jetty.jaas.spi.PropertyFileLoginModule required
        debug="true"
        file="/somewhere/somefile.props";
      };

The file parameter is the location of a properties file of the same format as the etc/realm.properties example file. The format is:

<username>: <password>[,<rolename> ...]

Here’s an example:

fred: OBF:1xmk1w261u9r1w1c1xmq,user,admin
harry: changeme,user,developer
tom: MD5:164c88b302622e17050af52c89945d44,user
dick: CRYPT:adpexzg3FUZAk,admin

The contents of the file are fully read in and cached in memory the first time a user requests authentication.

LdapLoginModule

Here’s an example:

ldaploginmodule {
   org.eclipse.jetty.jaas.spi.LdapLoginModule required
   debug="true"
   contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
   hostname="ldap.example.com"
   port="389"
   bindDn="cn=Directory Manager"
   bindPassword="directory"
   authenticationMethod="simple"
   forceBindingLogin="false"
   userBaseDn="ou=people,dc=alcatel"
   userRdnAttribute="uid"
   userIdAttribute="uid"
   userPasswordAttribute="userPassword"
   userObjectClass="inetOrgPerson"
   roleBaseDn="ou=groups,dc=example,dc=com"
   roleNameAttribute="cn"
   roleMemberAttribute="uniqueMember"
   roleObjectClass="groupOfUniqueNames";
   };

Writing your Own LoginModule

If you want to implement your own custom LoginModule, there are two classes to be familiar with: org.eclipse.jetty.jaas.spi.AbstractLoginModule and org.eclipse.jetty.jaas.spi.UserInfo.

The org.eclipse.jetty.jaas.spi.AbstractLoginModule implements all of the javax.security.auth.spi.LoginModule methods. All you need to do is to implement the getUserInfo method to return a org.eclipse.jetty.jaas.UserInfo instance which encapsulates the username, password and role names (note: as java.lang.Strings) for a user.

The AbstractLoginModule does not support any caching, so if you want to cache UserInfo (eg as does the org.eclipse.jetty.jaas.spi.PropertyFileLoginModule) then you must provide this yourself.

Other Goodies

ServletRequestCallback

This callback gives you access to the ServletRequest that is involved in the authentication, and thus to other features like the current Session. This callback can be configured in your custom LoginModule implementation. Note that none of the LoginModule implementations provided with Jetty currently use this callback.

RequestParameterCallback

As all servlet containers intercept and process a form submission with action j_security_check, it is usually not possible to insert any extra input fields onto a login form with which to perform authentication: you may only pass j_username and j_password. For those rare occasions when this is not good enough, and you require more information from the user in order to authenticate them, you can use the JAAS callback handler org.eclipse.jetty.jaas.callback.RequestParameterCallback. This callback gives you access to all parameters that were passed in the form submission. To use it, in the login() method of your custom login module, add the RequestParameterCallback to the list of callback handlers the login module uses, tell it which params you are interested in, and then get the value of the parameter back. Here is an example:

public class FooLoginModule extends AbstractLoginModule
{
     public boolean login()
        throws LoginException
     {

        Callback[] callbacks = new Callback[3];
        callbacks[0] = new NameCallback();
        callbacks[1] = new ObjectCallback();

        //as an example, look for a param named "extrainfo" in the request
        //use one RequestParameterCallback() instance for each param you want to access
        callbacks[2] = new RequestParameterCallback ();
        ((RequestParameterCallback)callbacks[2]).setParameterName ("extrainfo");


        callbackHandler.handle(callbacks);
        String userName = ((NameCallback)callbacks[0]).getName();
        Object pwd = ((ObjectCallback)callbacks[1]).getObject();
        List paramValues = ((RequestParameterCallback)callbacks[2]).getParameterValues();

        //use the userName, pwd and the value(s) of the parameter named "extrainfo" to
        //authenticate the user

     }
}
Example JAAS WebApp

An example webapp using JAAS can be found in the Jetty GitHub repository:

SPNEGO Support

Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) is a way for users to be seamlessly authenticated when running on systems that rely on Kerberos for authentication, such as Windows Active Directory based networks.

Jetty supports this type of authentication and authorization through the JDK (which has been enabled since the later versions of Java 6 and 7).

Configuring Jetty and SPNEGO

To run with SPNEGO enabled the following command line options are required:

-Djava.security.krb5.conf=/path/to/krb5.ini

For debugging the SPNEGO authentication the following options are helpful:

-Dorg.eclipse.jetty.LEVEL=debug
-Dsun.security.spnego.debug=true
-Dsun.security.jgss.debug=true
-Dsun.security.krb5.debug=true

SPNEGO authentication must be enabled in the webapp in the following way. The name of the role will be different for your network.

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Secure Area</web-resource-name>
    <url-pattern>/secure/me/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <!-- this is the domain that the user is a member of -->
    <role-name>MORTBAY.ORG</role-name>
  </auth-constraint>
</security-constraint>
<login-config>
  <auth-method>SPNEGO</auth-method>
  <realm-name>Test Realm</realm-name>
  <!-- optionally to add custom error page -->
  <spnego-login-config>
    <spnego-error-page>/loginError.html?param=foo</spnego-error-page>
  </spnego-login-config>
</login-config>

A corresponding UserRealm needs to be created either programmatically if embedded, via the jetty.xml or in a context file for the webapp.

This is what the configuration within a context XML file would look like:

<Get name="securityHandler">
  <Set name="loginService">
    <New class="org.eclipse.jetty.security.SPNEGOLoginService">
      <Arg>Test Realm</Arg>
      <Arg><Ref refid="authorizationService" /></Arg>
      <Set name="keyTabPath"><Ref refid="keyTabPath" /></Set>
    </New>
  </Set>
</Get>

On the Windows Active Domain Controller run:

$ setspn -A HTTP/linux.mortbay.org ADUser

To create the keyTab file use the following process:

$ ktpass -out c:\dir\krb5.keytab -princ HTTP/linux.mortbay.org@MORTBAY.ORG -mapUser ADUser -mapOp set -pass ADUserPWD -crypto RC4-HMAC-NT -pType KRB5_NT_PRINCIPAL

This step will give you the keyTab file which should then be copied to the machine running the http server and referenced from the configuration files.

Configuring Firefox

The follows steps have been required to inform Firefox that it should use a negotiation dialog to authenticate.

  1. Browse to about:config and agree to the warnings

  2. Search through to find the 'network' settings

  3. Set network.negotiate-auth.delegation-uris to http://,https://

  4. Set network.negotiate-auth.trusted-uris to http://,https://

Configuring Internet Explorer

The follows steps have been required to inform Internet Explorer that it should use a negotiation dialog to authenticate.

  1. Tools → Options → Security → Local Intranet → Sites (everything should be checked here)

  2. Tools → Options → Security → Local Intranet → Sites → Advanced (add url to server (http:// and/or https:// — use the hostname, not the IP)

  3. Tools → Options → Security → Local Intranet → Sites → Advanced → Close

  4. Tools → Options → Security → Local Intranet → Sites → Ok

  5. Tools → Options → Advanced → Security (in the checkbox list)

  6. Locate and select Enable Integrated Windows Authentication

  7. Tools → Options → Advanced → Security → Ok

  8. Close IE then reopen and browse to your SPNEGO protected resource

You must use hostname and not the IP. If you use the IP it will default to NTLM authentication. The following conditions must be true for SPNEGO authentication to work:

  • You must be within the Intranet Zone of the network

  • Access the server using a Hostname rather than IP

  • Integrated Windows Authentication in IE is enabled and/or the host is trusted in Firefox

  • The server is not local to the browser; it can’t be running on localhost

  • The client’s Kerberos system is authenticated to a domain controller

OpenID Support

External Setup

Registering an App with OpenID Provider

You must register the app with an OpenID Provider such as Google or Amazon. This will give you a Client ID and Client Secret. Once set up you must also register all the possible URI’s for your webapp with the path /j_security_check so that the OpenId Provider will allow redirection back to the webapp.

These may look like

Distribution Configuration

OpenID Provider Configuration

To enable OpenID support, you first need to activate the openid module in your implementation.

$ java -jar $JETTY_HOME/start.jar --add-to-start=openid

To configure OpenID Authentication with Jetty you will need to specify the OpenID Provider’s issuer identifier (case sensitive URL using the https scheme) and the OAuth 2.0 Client ID and Client Secret. If the OpenID Provider does not allow metadata discovery you will also need to specify the token endpoint and authorization endpoint of the OpenID Provider. These can be set as properties in the start.ini or start.d/openid.ini files.

WebApp Specific Configuration in web.xml

The web.xml file needs some specific configuration to use OpenID. There must be a login-config element with an auth-method value of OPENID, and a realm-name value of the exact URL string used to set the OpenID Provider.

To set the error page, an init param is set at "org.eclipse.jetty.security.openid.error_page", its value should be a path relative to the webapp where authentication errors should be redirected.

Example:

<login-config>
  <auth-method>OPENID</auth-method>
  <realm-name>https://accounts.google.com</realm-name>
</login-config>
<context-param>
  <param-name>org.eclipse.jetty.security.openid.error_page</param-name>
  <param-value>/error</param-value>
</context-param>

Embedded Configuration

Define the OpenIdConfiguration for a specific OpenID Provider.

If the OpenID Provider allows metadata discovery then you can use.

OpenIdConfiguration openIdConfig = new OpenIdConfiguration(ISSUER, CLIENT_ID, CLIENT_SECRET);

Otherwise you can manually enter the necessary information:

OpenIdConfiguration openIdConfig = new OpenIdConfiguration(ISSUER, TOKEN_ENDPOINT, AUTH_ENDPOINT, CLIENT_ID, CLIENT_SECRET);
Configuring an OpenIdLoginService
LoginService loginService = new OpenIdLoginService(openIdConfig);
securityHandler.setLoginService(loginService);
Configuring an OpenIdAuthenticator with OpenIdConfiguration and Error Page Redirect
Authenticator authenticator = new OpenIdAuthenticator(openIdConfig, "/error");
securityHandler.setAuthenticator(authenticator);
servletContextHandler.setSecurityHandler(securityHandler);
Usage
Claims and Access Token

Claims about the user can be found using attributes on the session attribute "org.eclipse.jetty.security.openid.claims", and the full response containing the OAuth 2.0 Access Token can be found with the session attribute "org.eclipse.jetty.security.openid.response".

Example:

Map<String, Object> claims = (Map)request.getSession().getAttribute("org.eclipse.jetty.security.openid.claims");
String userId = claims.get("sub");

Map<String, Object> response = (Map)request.getSession().getAttribute("org.eclipse.jetty.security.openid.response");
String accessToken = response.get("access_token");

Scopes

The OpenID scope is always used but additional scopes can be requested which can give you additional resources or privileges. For the Google OpenID Provider it can be useful to request the scopes profile and email which will give you additional user claims.

Additional scopes can be requested through the start.ini or start.d/openid.ini files, or with OpenIdConfiguration.addScopes(…​); in embedded code.

Roles

If security roles are required they can be configured through a wrapped LoginService which is deferred to for role information by the OpenIdLoginService.

This can be configured in XML through etc/openid-baseloginservice.xml in the Distribution, or in embedded code using the constructor for the OpenIdLoginService.

LoginService wrappedLoginService = ...; // Optional LoginService for Roles
LoginService loginService = new OpenIdLoginService(openIdConfig, wrappedLoginService);

When using authorization roles, the setting authenticateNewUsers becomes significant. If set to true users not found by the wrapped LoginService will still be authenticated but will have no roles. If set to false those users will be not be allowed to authenticate and are redirected to the error page. This setting is configured through the property jetty.openid.authenticateNewUsers in the start.ini or start.d/openid.ini file, or with OpenIdLoginService.setAuthenticateNewUsers(…​); in embedded code.

Starting Jetty

Startup a Unix Service using jetty.sh

The standalone Jetty distribution ships with a bin/jetty.sh script that can be used by various Unix distros (including OSX) to manage Jetty as a startup service.

This script is suitable for setting up Jetty as a service in Unix.

Quick-Start a Jetty Service

The minimum steps to get Jetty to run as a Service include:

[/opt/jetty]# tar -zxf /home/user/downloads/jetty-home-12.0.9-SNAPSHOT.tar.gz
[/opt/jetty]# cd jetty-home-12.0.9-SNAPSHOT/
[/opt/jetty/jetty-home-12.0.9-SNAPSHOT]# ls
bin        lib                         modules      resources  start.jar
demo-base  license-eplv10-aslv20.html  notice.html  start.d    VERSION.txt
etc        logs                        README.TXT   start.ini  webapps

[/opt/jetty/jetty-home-12.0.9-SNAPSHOT]# cp bin/jetty.sh /etc/init.d/jetty
[/opt/jetty/jetty-home-12.0.9-SNAPSHOT]# echo JETTY_HOME=`pwd` > /etc/default/jetty
[/opt/jetty/jetty-home-12.0.9-SNAPSHOT]# cat /etc/default/jetty
JETTY_HOME=/opt/jetty/jetty-home-12.0.9-SNAPSHOT

[/opt/jetty/jetty-home-12.0.9-SNAPSHOT]# service jetty start
Starting Jetty: OK Wed Nov 20 10:26:53 MST 2013

From this demonstration we can see that Jetty started successfully as a Unix Service from the /opt/jetty/jetty-home-12.0.9-SNAPSHOT directory.

This configuration works well but it is running Jetty as the root user.

Practical Setup of a Jetty Service

There are various ways this can be accomplished, mostly depending on your Unix environment (and possibly corporate policies).

The techniques outlined here assume an installation on Linux (demonstrated on Ubuntu 12.04.3 LTS).

Prepare some empty directories to work with.

# mkdir -p /opt/jetty
# mkdir -p /opt/web/mybase
# mkdir -p /opt/jetty/temp

The directory purposes are as follows:

/opt/jetty

Where the Jetty Distribution will be unpacked into

/opt/web/mybase

Where your specific set of webapps will be located, including all of the configuration required of the server to make them operational.

/opt/jetty/temp

This is the temporary directory assigned to Java by the Service Layer (this is what Java sees as the java.io.tmpdir System Property).

This is intentionally kept separate from the standard temp directory of /tmp, as this location doubles as the Servlet Spec work directory. It is our experience that the standard temp directory is often managed by various cleanup scripts that wreak havoc on a long running Jetty server.

Jetty 9.3 requires Java 8 (or greater) to run. Make sure you have it installed.

# apt-get install openjdk-8-jdk
# java -version
java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1ubuntu0.12.04.2)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

# update-alternatives --list java
/usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java
/usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java

# update-alternatives --config java
There are 2 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                            Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java   1061      auto mode
  1            /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java   1061      manual mode
  2            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1051      manual mode

Press enter to keep the current choice[*], or type selection number: 2
update-alternatives: using /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java to provide /usr/bin/java (java) in manual mode.

# java -version
java version "1.7.0_25"
OpenJDK Runtime Environment (IcedTea 2.3.10) (7u25-2.3.10-1ubuntu0.12.04.2)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)

It is recommended that you create a user to specifically run Jetty. This user should have the minimum set of privileges needed to run Jetty.

# useradd --user-group --shell /bin/false --home-dir /opt/jetty/temp jetty

This will create a user called jetty, belonging to the group called jetty, with no shell access (aka /bin/false), and home directory at /opt/jetty/temp.

Download a copy of the Jetty distribution from the Official Eclipse Download Site

Unpack it into place.

[/opt/jetty]# tar -zxf /home/user/Downloads/jetty-home-12.0.9-SNAPSHOT.tar.gz
[/opt/jetty]# ls -F
jetty-home-12.0.9-SNAPSHOT/
[/opt/jetty]# mkdir /opt/jetty/temp

It might seem strange or undesirable to unpack the first portion of the jetty-home directory name too. But starting with Jetty 9 the split between ${jetty.home} and ${jetty.base} allows for easier upgrades of Jetty itself while isolating your webapp specific configuration. For more information on the Jetty home and base concepts see the section on managing a Jetty installation earlier in this Chapter.

The /opt/jetty/temp directory is created as a durable place for Jetty to use for temp and working directories. Many Unix systems will periodically clean out the /tmp directory, this behavior is undesired in a Servlet container and has been known to cause problems. This durable directory at /opt/jetty/temp solves for that behavior.

The directory at /opt/web/mybase is going to be a ${jetty.base}, so lets configure it to hold your webapp and its configuration.

In past versions of Jetty, you would configure / modify / add to the jetty-home directory directly. While this is still supported, we encourage you to setup a proper ${jetty.base} directory, as it will benefit you with easier jetty-home upgrades in the future.

# cd /opt/web/mybase/
[/opt/web/mybase]# ls
[/opt/web/mybase]# java -jar /opt/jetty/jetty-home-12.0.9-SNAPSHOT/start.jar \
   --add-to-start=deploy,http,console-capture
   INFO  : webapp          transitively enabled, ini template available with --add-to-start=webapp
   INFO  : server          transitively enabled, ini template available with --add-to-start=server
   INFO  : security        transitively enabled
   INFO  : servlet         transitively enabled
   INFO  : console-capture initialized in ${jetty.base}/start.ini
   INFO  : http            initialized in ${jetty.base}/start.ini
   INFO  : deploy          initialized in ${jetty.base}/start.ini
   MKDIR : ${jetty.base}/logs
   MKDIR : ${jetty.base}/webapps
   INFO  : Base directory was modified
[/opt/web/mybase]# ls -F
start.ini  webapps/

At this point you have configured your /opt/web/mybase to enable the following modules:

deploy

This is the module that will perform deployment of web applications (WAR files or exploded directories), or Jetty IoC XML context deployables, from the /opt/web/mybase/webapps directory.

http

This sets up a single Connector that listens for basic HTTP requests.

See the created start.ini for configuring this connector.

console-capture

When running Jetty as a service it is very important to have logging enabled. This module will enable the basic STDOUT and STDERR capture logging to the /opt/web/mybase/logs/ directory.

Additionally, the webapp, server, security and servlet modules were enabled as they are dependencies for other modules.

See [start-jar] for more details and options on setting up and configuring a ${jetty.base} directory.

Copy your war file into place.

# cp /home/user/projects/mywebsite.war /opt/web/mybase/webapps/

Most service installations will want Jetty to run on port 80, now is the opportunity to change this from the default value of 8080 to 80.

Edit the /opt/web/mybase/start.ini and change the jetty.http.port value.

# grep jetty.http.port /opt/web/mybase/start.ini
jetty.port=80

Change the permissions on the Jetty distribution and webapp directories so that the user you created can access it.

# chown --recursive jetty /opt/jetty
# chown --recursive jetty /opt/web/mybase

Next we need to make the Unix System aware that we have a new Jetty Service that can be managed by the standard service calls.

# cp /opt/jetty/jetty-home-12.0.9-SNAPSHOT/bin/jetty.sh /etc/init.d/jetty
# echo "JETTY_HOME=/opt/jetty/jetty-home-12.0.9-SNAPSHOT" > /etc/default/jetty
# echo "JETTY_BASE=/opt/web/mybase" >> /etc/default/jetty
# echo "TMPDIR=/opt/jetty/temp" >> /etc/default/jetty

Test out the configuration:

# service jetty status
Checking arguments to Jetty:
START_INI      =  /opt/web/mybase/start.ini
JETTY_HOME     =  /opt/jetty/jetty-home-12.0.9-SNAPSHOT
JETTY_BASE     =  /opt/web/mybase
JETTY_CONF     =  /opt/jetty/jetty-home-12.0.9-SNAPSHOT/etc/jetty.conf
JETTY_PID      =  /var/run/jetty.pid
JETTY_START    =  /opt/jetty/jetty-home-12.0.9-SNAPSHOT/start.jar
CLASSPATH      =
JAVA           =  /usr/bin/java
JAVA_OPTIONS   =  -Djetty.state=/opt/web/mybase/jetty.state
       -Djetty.logs=/opt/web/mybase/logs
       -Djetty.home=/opt/jetty/jetty-home-12.0.9-SNAPSHOT
       -Djetty.base=/opt/web/mybase
       -Djava.io.tmpdir=/opt/jetty/temp
JETTY_ARGS     =  console-capture.xml jetty-started.xml
RUN_CMD        =  /usr/bin/java
       -Djetty.state=/opt/web/mybase/jetty.state
       -Djetty.logs=/opt/web/mybase/logs
       -Djetty.home=/opt/jetty/jetty-home-12.0.9-SNAPSHOT
       -Djetty.base=/opt/web/mybase
       -Djava.io.tmpdir=/opt/jetty/temp
       -jar /opt/jetty/jetty-home-12.0.9-SNAPSHOT/start.jar
       console-capture.xml
       jetty-started.xml

You now have a configured ${jetty.base} in /opt/web/mybase and a ${jetty.home} in /opt/jetty/jetty-home-12.0.9-SNAPSHOT, along with the service level files necessary to start the service.

Test the service to make sure it starts up and runs successfully.

# service jetty start
Starting Jetty: OK Wed Nov 20 12:35:28 MST 2013

# service jetty check
..(snip)..
Jetty running pid=2958

[/opt/web/mybase]# ps u 2958
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
jetty     2958  5.3  0.1 11179176 53984 ?      Sl   12:46   0:00 /usr/bin/java -Djetty...

You should now have your server running.

Startup via Windows Service

There are no components that ship with the Jetty Distribution to make it a formal Windows Service.

However, we recommend the use of Apache ProcRun’s Daemon.

The techniques outlined here are based on Windows 7 (64-bit), using JDK 8 (64-bit), running on an Intel i7 architecture machine.

Prepare some empty directories to work with.

C:\> mkdir opt
C:\> cd opt
C:\opt> mkdir jetty
C:\opt> mkdir logs
C:\opt> mkdir myappbase
C:\opt> mkdir temp
C:\opt> dir
 Volume in drive C has no label.
 Volume Serial Number is DEAD-BEEF

 Directory of C:\opt

11/21/2013  04:06 PM    <DIR>          .
11/21/2013  04:06 PM    <DIR>          ..
11/21/2013  04:06 PM    <DIR>          jetty
11/21/2013  04:06 PM    <DIR>          logs
11/21/2013  04:06 PM    <DIR>          myappbase
11/21/2013  04:06 PM    <DIR>          temp
               0 File(s)              0 bytes

The directory purposes are as follows:

C:\opt

Where the service layer utilities, scripts, and binaries will eventually be.

C:\opt\logs

Where the logs for the service layer will put its own logs.

Typically you will see the audit logs (install/update/delete), StdOutput, and StdError logs here.

C:\opt\jetty

Where the Jetty Distribution will be unpacked into.

C:\opt\myappbase

Where your specific set of webapps will be located, including all of the configuration required of the server to make them operational.

C:\opt\temp

This is the temporary directory assigned to Java by the Service Layer (this is what Java sees as the java.io.tmpdir System Property).

This is intentionally kept separate from the standard temp directories of Windows, as this location doubles as the Servlet Spec work directory.

C:\opt>java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

Download a copy of the ZIP distribution from the Official Eclipse Download Site

Extract the contents of the jetty-home-12.0.9-SNAPSHOT directory to C:\opt\jetty

Once complete, the contents of the C:\opt\jetty directory should look like this:

C:\opt\jetty>dir
 Volume in drive C has no label.
 Volume Serial Number is C8CF-820B

 Directory of C:\opt\jetty

11/21/2013  12:13 PM    <DIR>          .
11/21/2013  12:13 PM    <DIR>          ..
11/21/2013  12:13 PM    <DIR>          bin
11/21/2013  12:13 PM    <DIR>          demo-base
11/21/2013  12:13 PM    <DIR>          etc
11/21/2013  12:13 PM    <DIR>          lib
11/21/2013  12:13 PM            30,012 license-eplv10-aslv20.html
11/21/2013  12:13 PM    <DIR>          logs
11/21/2013  12:13 PM    <DIR>          modules
11/21/2013  12:13 PM             6,262 notice.html
11/21/2013  12:13 PM             1,249 README.TXT
11/21/2013  12:13 PM    <DIR>          resources
11/21/2013  12:13 PM    <DIR>          start.d
11/21/2013  12:13 PM             2,126 start.ini
11/21/2013  12:13 PM            72,226 start.jar
11/21/2013  12:13 PM           341,784 VERSION.txt
11/21/2013  12:13 PM    <DIR>          webapps
               6 File(s)        453,659 bytes
              11 Dir(s)  306,711,420,928 bytes free

Download a copy of the Apache ProcRun native binaries.

You should have downloaded a file named commons-daemon-1.0.15-bin-windows.zip (the version might be different). Open the ZIP file and extract the prunmgr.exe and prunsrv.exe files into the C:\opt directory.

Make sure to get the right version of prunsrv.exe for your environment. The ZIP file has both 32 bit and 64 bit versions of this file.

Once you are complete, the contents of C:\opt directory should look like this:

C:\opt> dir
 Volume in drive C has no label.
 Volume Serial Number is DEAD-BEEF

 Directory of C:\opt

11/21/2013  04:06 PM    <DIR>          .
11/21/2013  04:06 PM    <DIR>          ..
11/21/2013  04:06 PM    <DIR>          jetty
11/21/2013  04:06 PM    <DIR>          logs
11/21/2013  04:06 PM    <DIR>          myappbase
11/21/2013  04:06 PM    <DIR>          temp
11/21/2013  04:11 PM           104,448 prunmgr.exe
11/21/2013  04:11 PM            80,896 prunsrv.exe
               2 File(s)        185,344 bytes

Now it’s time to setup your new ${jetty.base} directory to have all of your WebApps and the configurations that they need.

We’ll start by specifying which modules we want to use (this will create a start.ini file and also create a few empty directories for you)

C:\opt\myappbase>java -jar ..\jetty\start.jar --add-to-start=deploy,http,console-capture

WARNING: deploy          initialised in ${jetty.base}\start.ini (appended)
WARNING: deploy          enabled in     ${jetty.base}\start.ini
MKDIR: ${jetty.base}\webapps
WARNING: server          initialised in ${jetty.base}\start.ini (appended)
WARNING: server          enabled in     ${jetty.base}\start.ini
WARNING: http            initialised in ${jetty.base}\start.ini (appended)
WARNING: http            enabled in     ${jetty.base}\start.ini
WARNING: server          enabled in     ${jetty.base}\start.ini
WARNING: logging         initialised in ${jetty.base}\start.ini (appended)
WARNING: logging         enabled in     ${jetty.base}\start.ini
MKDIR: ${jetty.base}\logs

C:\opt\myappbase>dir
 Volume in drive C has no label.
 Volume Serial Number is C8CF-820B

 Directory of C:\opt\myappbase

11/21/2013  12:49 PM    <DIR>          .
11/21/2013  12:49 PM    <DIR>          ..
11/21/2013  12:49 PM    <DIR>          logs
11/21/2013  12:49 PM             1,355 start.ini
11/21/2013  12:49 PM    <DIR>          webapps
               1 File(s)          1,355 bytes
               4 Dir(s)  306,711,064,576 bytes free

At this point you have configured your C:\opt\myappbase to enable the following modules:

deploy

This is the module that will perform deployment of web applications (WAR files or exploded directories), or Jetty IoC XML context deployables, from the C:\opt\myappbase\webapps directory.

http

This sets up a single Connector that listens for basic HTTP requests.

See the created start.ini for configuring this connector.

logging

When running Jetty as a service it is very important to have logging enabled. This module will enable the basic STDOUT and STDERR capture logging to the C:\opt\myappbase\logs directory.

See the section on [start-jar] for more details and options on setting up and configuring a ${jetty.base} directory.

At this point you merely have to copy your WAR files into the {$jetty.base}/webapps directory.

C:\opt\myappbase> copy C:\projects\mywebsite.war webapps\

At this point you should have your directories, Java, the Jetty distribution, and your webapp specifics setup and ready for operation.

We will use the Apache ProcRun’s prunsrv.exe to install a Jetty Service.

The basic command line syntax is outlined in the link above.

A example install-jetty-service.bat is provided here as an example, based on the above directories.

@echo off
set SERVICE_NAME=JettyService
set JETTY_HOME=C:\opt\jetty
set JETTY_BASE=C:\opt\myappbase
set STOPKEY=secret
set STOPPORT=50001

set PR_INSTALL=C:\opt\prunsrv.exe

@REM Service Log Configuration
set PR_LOGPREFIX=%SERVICE_NAME%
set PR_LOGPATH=C:\opt\logs
set PR_STDOUTPUT=auto
set PR_STDERROR=auto
set PR_LOGLEVEL=Debug

@REM Path to Java Installation
set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_45
set PR_JVM=%JAVA_HOME%\jre\bin\server\jvm.dll
set PR_CLASSPATH=%JETTY_HOME%\start.jar;%JAVA_HOME%\lib\tools.jar

@REM JVM Configuration
set PR_JVMMS=128
set PR_JVMMX=512
set PR_JVMSS=4000
set PR_JVMOPTIONS=-Duser.dir="%JETTY_BASE%";-Djava.io.tmpdir="C:\opt\temp";-Djetty.home="%JETTY_HOME%";-Djetty.base="%JETTY_BASE%"
@REM Startup Configuration
set JETTY_START_CLASS=org.eclipse.jetty.start.Main

set PR_STARTUP=auto
set PR_STARTMODE=java
set PR_STARTCLASS=%JETTY_START_CLASS%
set PR_STARTPARAMS=STOP.KEY="%STOPKEY%";STOP.PORT=%STOPPORT%

@REM Shutdown Configuration
set PR_STOPMODE=java
set PR_STOPCLASS=%JETTY_START_CLASS%
set PR_STOPPARAMS=--stop;STOP.KEY="%STOPKEY%";STOP.PORT=%STOPPORT%;STOP.WAIT=10

"%PR_INSTALL%" //IS/%SERVICE_NAME% ^
  --DisplayName="%SERVICE_NAME%" ^
  --Install="%PR_INSTALL%" ^
  --Startup="%PR_STARTUP%" ^
  --LogPath="%PR_LOGPATH%" ^
  --LogPrefix="%PR_LOGPREFIX%" ^
  --LogLevel="%PR_LOGLEVEL%" ^
  --StdOutput="%PR_STDOUTPUT%" ^
  --StdError="%PR_STDERROR%" ^
  --JavaHome="%JAVA_HOME%" ^
  --Jvm="%PR_JVM%" ^
  --JvmMs="%PR_JVMMS%" ^
  --JvmMx="%PR_JVMMX%" ^
  --JvmSs="%PR_JVMSS%" ^
  --JvmOptions=%PR_JVMOPTIONS% ^
  --Classpath="%PR_CLASSPATH%" ^
  --StartMode="%PR_STARTMODE%" ^
  --StartClass="%JETTY_START_CLASS%" ^
  --StartParams="%PR_STARTPARAMS%" ^
  --StopMode="%PR_STOPMODE%" ^
  --StopClass="%PR_STOPCLASS%" ^
  --StopParams="%PR_STOPPARAMS%"

if not errorlevel 1 goto installed
echo Failed to install "%SERVICE_NAME%" service.  Refer to log in %PR_LOGPATH%
goto end

:installed
echo The Service "%SERVICE_NAME%" has been installed

:end

Configuration’s of note in this batch file:

SERVICE_NAME

This is the name of the service that Windows sees. The name in the Services window will show this name.

STOPKEY

This is the secret key (password) for the ShutdownMonitor, used to issue a formal command to stop the server.

STOPPORT

The port that the Shutdown Monitor listens on for the stop command.

If you have multiple Jetty servers on the same machine, this port will need to be different for each Service.

Once you have run prunsrv.exe //IS/<service-name> (done for you in the above batch file) to install the service, you can use the standard Windows utilities to manage (start/stop/restart) the Jetty service.

Open the Service View and start your service.

image

Troubleshooting

This is a collection of helpful tricks and tips that we have come across to address odd issues that might arise.

Troubleshooting Zip Exceptions

A Zip exception occurs when Jetty rereads a Jar or WAR file.

The JVM maintains a cache of zip file indexes, and does not support hot replacement of zip files. Thus if you redeploy a web application using the same WAR or Jar files, exceptions occur when Jetty rereads the jars. See Oracle Bug 4774421 for more information.

Remedy

The remedy is to avoid hot replacing Jar or WAR files, which can be difficult if you are using the Webapp Provider. You can use the following techniques to reduce exposure to this issue:

  • Deploy unpacked classes in the WEB-INF/classes directory rather than as a Jar file under WEB-INF/lib.

  • Deploy all WAR and Jar files with a version number in their filename or path. If the code changes, a new version number applies, avoiding the cache problem.

  • Deploy a packed WAR file with the setExtractWAR option set to true. This causes the WAR to be extracted to a temporary directory and thus to a new location. This might not be sufficient if you want to hot-replace and re-extract the WAR, so you might also need to use WebAppContext.setCopyWebInf(true), which (re)copies just the WEB-INF directory to a different location.

  • Deploy an unpacked WAR file with the setCopyWebDir option set to true. This causes the directory to be extracted to a new location.

If you have problems with Windows file-locking preventing static file editing (such as JSP or HTML), use the WebAppContext .setCopyWebDir(true) option.

Troubleshooting Locked Files on Windows

Jetty buffers static content for webapps such as HTML files, CSS files, images, etc. If you are using NIO connectors, Jetty uses memory-mapped files to do this. The problem is that on Windows, memory mapping a file causes the file to lock, so that you cannot update or replace the file. Effectively this means that you have to stop Jetty to update a file.

Remedy

Jetty provides a configuration switch for the DefaultServlet that enables or disables the use of memory-mapped files. If you are running on Windows and are having file-locking problems, you should set this switch to disable memory-mapped file buffers. Use one of the following options to configure the switch.

Using override-web.xml

An override-web.xml file can be placed in your webapp’s WEB-INF directory to change the default setting of the DefaultServlet for memory-mapped file buffers. Create an override-web.xml file with appropriate headers for your version of the servlet specification, and place the following inside the <web-app> element:

 <servlet>
   <servlet-name>default</servlet-name>
   <init-param>
     <param-name>useFileMappedBuffer</param-name>
     <param-value>false</param-value>
   </init-param>
 </servlet>
Using a Context XML File

You can create or update a context xml file that configures your webapp to apply the setting to disable memory-mapped file buffers. Add the following to your context xml file:

  <Call name="setInitParameter">
      <Arg>org.eclipse.jetty.ee9.servlet.Default.useFileMappedBuffer</Arg>
      <Arg>false</Arg>
  </Call>
Using the Jetty Maven Plugin

If you don’t want to use either of the other two solutions, you can configure the plugin directly to disable memory-mapped file buffers. Add the following to the plugin’s configuration under the <webApp> element:

  <_initParams>
          <org.eclipse.jetty.ee9.servlet.Default.useFileMappedBuffer>false</org.eclipse.jetty.ee9.servlet.Default.useFileMappedBuffer>
  </_initParams>

Alternate Remedy

You can force a WebAppContext to always copy a web app directory on deployment. The base directory of your web app (i.e. the root directory where your static content exists) will be copied to the temp directory. Configure this in an xml file like so:

<New id="myWebAppContext"  class="org.eclipse.jetty.ee9.webapp.WebAppContext">
  <Set name="contextPath">/</Set>
  <Set name="war">./webapps/fredapp</Set>
  <Set name="copyWebDir">true</Set>
  .
  .
</New>
Be careful with this option when using an explicitly settemp directory name - as the name of the temp directory will not unique across redeployments, copying the static content into the same directory name each time may not avoid the locking problem.

Preventing Memory Leaks

If you have memory leaks, and you have thoroughly investigated tools like jconsole, yourkit, jprofiler, jvisualvm or any of the other profiling and analysis tools, and you can eliminate your code as the source of the problem, read the following sections about how to prevent memory leaks in your application.

Preventing WebApp Classloader Pinning

This feature is available for Jetty 7.6.6 and later.

Code that keeps references to a webapp classloader can cause memory leaks. These leaks fall generally into two categories: static fields and daemon threads.

  • A static field is initialized with the value of the classloader, which happens to be a webapp classloader; as Jetty undeploys and redeploys the webapp, the static reference lives on, meaning garbage collecting cannot occur for the webapp classloader.

  • When Jetty starts as a daemon thread and is outside the lifecycle of the webapp, threads have references to the context classloader that created them, leading to a memory leak if that classloader belongs to a webapp. For a good discussion of the issue see Anatomy of a PermGen Memory Leak.

We provide a number of workaround classes that preemptively invoke the problematic code with the Jetty classloader, thereby ensuring the webapp classloader is not pinned. Be aware that since some of the problematic code creates threads, you should be selective about which preventers you enable, and use only those that are specific to your application.

Preventers

Jetty includes the following preventers.

Preventer Name Problem Addressed

AppContextLeakPreventer

The call to AppContext.getAppContext() keeps a static reference to the context classloader. The JRE can invoke AppContext in many different places.

AWTLeakPreventer

The java.awt.Toolkit class has a static field that is the default toolkit. Creating the default toolkit causes the creation of an EventQueue, which has a classloader field initialized with the thread context class loader. See JBoss bug AS7-3733.

DOMLeakPreventer

DOM parsing can cause the webapp classloader to be pinned, due to the static field ` RuntimeException` of com.sun.org.apache.xerces.internal.parsers.AbstractDOMParser. Oracle bug 6916498 specifically mentions that a heap dump might not identify the GCRoot as the uncollected loader, making it difficult to identify the cause of the leak.

DriverManagerLeakPreventer

The number of threads dedicated to accepting incoming connections.

GCThreadLeakPreventer

Calls to sun.misc.GC.requestLatency create a daemon thread that keeps a reference to the context classloader. A known caller of this method is the RMI impl. See Stackoverflow: Does java garbage collection log entry 'Full GC system' mean some class called System.gc()?

Java2DLeakPreventer

sun.java2d.Disposer keeps a reference to the classloader. See ASF bug 51687.

LDAPLeakPreventer

If com.sun.jndi.LdapPoolManager class is loaded and the system property ` com.sun.jndi.ldap.connect.pool.timeout` is set to a nonzero value, a daemon thread starts and keeps a reference to the context classloader.

LoginConfigurationLeakPreventer

The javax.security.auth.login.Configuration class keeps a static reference to the thread context classloader.

SecurityProviderLeakPreventer

Some security providers, such as sun.security.pkcs11.SunPKCS11 start a deamon thread that traps the thread context classloader.

Configuring Preventers

You can individually enable each preventer by adding an instance to a Server with the ` addBean(Object)` call. Here’s an example of how to do it in code with the org.eclipse.jetty.util.preventers.AppContextLeakPreventer:

Server server = new Server();
server.addBean(new AppContextLeakPreventer());

You can add the equivalent in code to the $JETTY_HOME/etc/jetty.xml file or any jetty xml file that is configuring a Server instance. Be aware that if you have more than one Server instance in your JVM, you should configure these preventers on just one of them. Here’s the example from code put into xml:

<Configure id="Server" class="org.eclipse.jetty.server.Server">

   <Call name="addBean">
    <Arg>
      <New class="org.eclipse.jetty.util.preventers.AppContextLeakPreventer"/>
    </Arg>
   </Call>

</Configure>

JSP Bugs: Permgen Problems

The JSP engine in Jetty is Jasper. This was originally developed under the Apache Tomcat project, but over time many different project have forked it. All Jetty versions up to 6 used Apache-based Jasper exclusively, with Jetty 6 using Apache Jasper only for JSP 2.0. With the advent of JSP 2.1, Jetty 6 switched to using Jasper from Sun’s Glassfish project, which is now the reference implementation.

All forks of Jasper suffer from a problem whereby using JSP tag files puts the permgen space under pressure. This is because of the classloading architecture of the JSP implementation. Each JSP file is effectively compiled and its class loaded in its own classloader to allow for hot replacement. Each JSP that contains references to a tag file compiles the tag if necessary and then loads it using its own classloader. If you have many JSPs that refer to the same tag file, the tag’s class is loaded over and over again into permgen space, once for each JSP. See Glassfish bug 3963 and Apache bug 43878. The Apache Tomcat project has already closed this bug with status WON’T FIX, however the Glassfish folks still have the bug open and have scheduled it to be fixed. When the fix becomes available, the Jetty project will pick it up and incorporate into our release program.

JVM Bugs

This section describes garbage collection and direct ByteBuffer problems.

Garbage Collection Problems

One symptom of a cluster of JVM related memory issues is the OOM exception accompanied by a message such as java.lang.OutOfMemoryError: requested xxxx bytes for xxx. Out of swap space?

Oracle bug 4697804 describes how this can happen in the scenario when the garbage collector needs to allocate a bit more space during its run and tries to resize the heap, but fails because the machine is out of swap space. One suggested work around is to ensure that the JVM never tries to resize the heap, by setting min heap size to max heap size:

java -Xmx1024m -Xms1024m

Another workaround is to ensure you have configured sufficient swap space on your device to accommodate all programs you are running concurrently.

Direct ByteBuffers

Exhausting native memory is another issue related to JVM bugs. The symptoms to look out for are the process size growing, but heap use remaining relatively constant. Both the JIT compiler and nio ByteBuffers can consume native memory. Oracle bug 6210541 discusses a still-unsolved problem whereby the JVM itself allocates a direct ByteBuffer in some circumstances while the system never garbage collects, effectively eating native memory. Guy Korland’s blog discusses this problem here and here. As the JIT compiler consumes native memory, the lack of available memory may manifest itself in the JIT as OutOfMemory exceptions such as Exception in thread "CompilerThread0" java.lang.OutOfMemoryError: requested xxx bytes for ChunkPool::allocate. Out of swap space?

By default, Jetty allocates and manages its own pool of direct ByteBuffers for io if you configure the nio SelectChannelConnector. It also allocates MappedByteBuffers to memory-map static files via the DefaultServlet settings. However, you could be vulnerable to this JVM ByteBuffer allocation problem if you have disabled either of these options. For example, if you’re on Windows, you may have disabled the use of memory-mapped buffers for the static file cache on the DefaultServlet to avoid the file-locking problem.

Troubleshooting Slow Deployment

After upgrading to a version of Jetty that supports Servlet Spec 3.0 or above, enabling some new modules, or introducing some new jars to your webapp, you notice that your deployment time is increased. This could be due to scanning for classes caused by a ServletContainerInitializer.

As documented in the section on Using Annotations, even if your webapp has set metadata-complete=true in web.xml, all jars within your webapp may still be scanned due to one or more ServletContainerInitializers that have a @HandlesTypes annotation listing the names of classes in which it is interested.

There are 3 ways to speed up deployment time:

  • limit which ServletContainerInitializers to include

  • limit which jars to scan

  • limit the scan to the first deployment only

Remedies

Limit Which ServletContainerInitializers to Execute

As documented in the section Excluding ServletContainerInitializers, you can provide a context attribute that defines a pattern of ServletContainerInitializer (SCI) class names to ignore. These SCIs will not be examined for @HandlesTypes and will not be executed. This is useful if you have included a 3rd party jar that has a SCI on which your code does not rely.

Limit Which Jars to Scan

As documented in the section Jars Scanned for Annotations, you can explicitly define which jars to include in the scanning process. This is helpful if you have a lot of jars in your webapp, and you know that they do not contain any classes referenced by an @HandlesTypes annotation on a ServletContainerInitializer that will be executed.

Limit Scanning to First Deployment Only (Quickstart)

The quickstart mechanism will do a normal deployment - obeying any limits on SCIs and jars to scan as documented here - the first time the webapp is deployed only. Subsequent deployments will re-use the information discovered during the first deployment. This is useful if you cannot limit the scan significantly by using any of the mechanisms described here, but you don’t want to incur the cost of scanning on every redeployment. The quickstart mechanism and how to use it is described here.

Jetty Security Reports

List of Security Reports

A current list of Jetty security reports can be viewed on the Project Home Page.

Reporting Security Issues

There are a number of avenues for reporting security issues to the Jetty project available.

If the issue is directly related to Jetty itself then reporting to the Jetty developers is encouraged. The most direct method is to mail security@webtide.com. Since Webtide is comprised of the active committers of the Jetty project this is our preferred reporting method. We are generally flexible in how we work with reporters of security issues but we reserve the right to act in the interests of the Jetty project in all circumstances.

If the issue is related to Eclipse or its Jetty integration then we encourage you to reach out to security@eclipse.org.

If the issue is related to integrations with Jetty we are happy to work with you to identify the proper entity and either of the approaches above is fine.

We prefer that security issues are reported directly to Jetty developers as opposed through GitHub Issues since it currently has no facility to tag issues as private.

Java WatchService

The JVM WatchService is in place to monitor objects like a directory for changes, and then update it’s contents and notify the application of those changes. This service is useful for features like Hot Deployment. When a change is detected, the WatchService will enter a "quiet time" where it is waiting for the change (or changes) to be made and completed before notifying the application of the change.

Example: A new war file is copied into /webapps. The WatchService can (depending on implementation) see that the file was created (which is registered as an event!, and that its growing in size (another event). With the quiet time, each of the events are gated behind that timeout before the aggregated events are sent to the application.

While some operating systems such as Windows have a native value for this quiet time, not all do, notably OSX. At the core this is a limitation of the JVM’s FileSystem-specific implementation, but one that has been raised to the attention of the project.

Remedy

To help offset the delay in systems like OSX, Jetty defaults the value for non-native implementations to a time of 5000ms. Using values lower than 5000ms is not recommended and has shown to frequently fail.

Optimizing Jetty

There are many ways to optimize Jetty which vary depending on the situation. Are you trying to optimize for number of requests within a given amount of time? Are you trying to optimize the serving of static content? Do you have a large bit of hardware that you want to give entirely over to Jetty to use to its heart’s delight? This chapter examines a few of the many different ways to optimize Jetty.

Garbage Collection

Tuning the JVM garbage collection (GC) can greatly improve the performance of the JVM where Jetty and your application are running. Optimal tuning of the GC depends on the behavior of the application(s) and requires detailed analysis, but there are general recommendations to follow to at least obtain comprehensive GC logs that can be later analyzed.

See official Java 8 and Java 9 Garbage Collection documentation for further assistance.

Garbage Collection Logging Configuration

These options are general to OpenJDK (and therefore also for the Oracle JVM). They provide good information about the GC activity of your JVM, producing logs that can later be analyzed to perform finer tuning.

JDK 8 Garbage Collection Logging Configuration
-Xloggc:/path/to/myjettybase/logs/gc.log
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
-XX:+ParallelRefProcEnabled
-XX:+PrintReferenceGC
-XX:+PrintTenuringDistribution
-XX:+PrintAdaptiveSizePolicy
JDK 9 Garbage Collection Logging Configuration
Xlog:gc*,ergo*=trace,ref*=debug,age*=trace:file=/path/to/myjettybase/logs/gc.log:time,level,tags

There are not many recommended options for GC that can apply to all users. However, the most obvious one is to disable explicit GC (this is performed regularly by RMI and can introduce an abnormal amount of GC pauses).

-XX:+DisableExplicitGC

High Load

Configuring Jetty for high load, whether for load testing or for production, requires that the operating system, the JVM, Jetty, the application, the network and the load generation all be tuned.

Load Generation for Load Testing

Machines handling load generation must have their OS, JVM, etc., tuned just as much as the server machines.

The load generation should not be over the local network on the server machine, as this has unrealistic performance and latency as well as different packet sizes and transport characteristics.

The load generator should generate a realistic load. Avoid the following pitfalls:

  • A common mistake is that load generators often open relatively few connections that are extremely busy sending as many requests as possible over each connection. This causes the measured throughput to be limited by request latency (see Lies, Damned Lies and Benchmarks for an analysis of such an issue).

  • Another common mistake is to use TCP/IP for a single request, and to open many, many short-lived connections. This often results in accept queues filling and limitations due to file descriptor and/or port starvation.

  • A load generator should model the traffic profile from the normal clients of the server. For browsers, this is often between two and six connections that are mostly idle and that are used in sporadic bursts with read times in between. The connections are typically long held HTTP/1.1 connections.

  • Load generators should be written in asynchronously so that a limited number of threads does not restrict the maximum number of users that can be simulated. If the generator is not asynchronous, a thread pool of 2000 may only be able to simulate 500 or fewer users. The Jetty HttpClient is an ideal choice for building a load generator as it is asynchronous and can simulate many thousands of connections (see the CometD Load Tester for a good example of a realistic load generator).

Operating System Tuning

Both the server machine and any load generating machines need to be tuned to support many TCP/IP connections and high throughput.

Linux

Linux does a reasonable job of self-configuring TCP/IP, but there are a few limits and defaults that you should increase. You can configure most of these in /etc/security/limits.conf or via sysctl.

TCP Buffer Sizes

You should increase TCP buffer sizes to at least 16MB for 10G paths and tune the auto-tuning (keep in mind that you need to consider buffer bloat).

$ sysctl -w net.core.rmem_max=16777216
$ sysctl -w net.core.wmem_max=16777216
$ sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
$ sysctl -w net.ipv4.tcp_wmem="4096 16384 16777216"
Queue Sizes

net.core.somaxconn controls the size of the connection listening queue. The default value is 128. If you are running a high-volume server and connections are getting refused at a TCP level, you need to increase this value. This setting can take a bit of finesse to get correct: if you set it too high, resource problems occur as it tries to notify a server of a large number of connections, and many remain pending, but if you set it too low, refused connections occur.

 $ sysctl -w net.core.somaxconn=4096

The net.core.netdev_max_backlog controls the size of the incoming packet queue for upper-layer (Java) processing. The default (2048) may be increased and other related parameters adjusted with:

$ sysctl -w net.core.netdev_max_backlog=16384
$ sysctl -w net.ipv4.tcp_max_syn_backlog=8192
$ sysctl -w net.ipv4.tcp_syncookies=1
Ports

If many outgoing connections are made (for example, on load generators), the operating system might run low on ports. Thus it is best to increase the port range, and allow reuse of sockets in TIME_WAIT:

$ sysctl -w net.ipv4.ip_local_port_range="1024 65535"
$ sysctl -w net.ipv4.tcp_tw_recycle=1
File Descriptors

Busy servers and load generators may run out of file descriptors as the system defaults are normally low. These can be increased for a specific user in /etc/security/limits.conf:

theusername            hard nofile     40000
theusername            soft nofile     40000
Congestion Control

Linux supports pluggable congestion control algorithms. To get a list of congestion control algorithms that are available in your kernel run:

$ sysctl net.ipv4.tcp_available_congestion_control

If cubic and/or htcp are not listed, you need to research the control algorithms for your kernel. You can try setting the control to cubic with:

$ sysctl -w net.ipv4.tcp_congestion_control=cubic
Mac OS

Tips welcome.

Windows

Tips welcome.

Network Tuning

Intermediaries such as nginx can use a non-persistent HTTP/1.0 connection. Make sure to use persistent HTTP/1.1 connections.

JVM Tuning
  • Tune the Garbage Collection

  • Allocate sufficient memory

  • Use the -server option

  • Jetty Tuning

Acceptors

The standard rule of thumb for the number of Accepters to configure is one per CPU on a given machine.

Low Resource Limits

Must not be configured for less than the number of expected connections.

Thread Pool

Configure with goal of limiting memory usage maximum available. Typically this is >50 and <500

Limiting Load

To achieve optimal fair handling for all users of a server, it can be necessary to limit the resources that each user/connection can utilize so as to maximize throughput for the server or to ensure that the entire server runs within the limitations of it’s runtime.

Low Resources Monitor

An instance of LowResourcesMonitor may be added to a Jetty server to monitor for low resources situations and to take action to limit the number of idle connections on the server. To configure the low resources monitor, you can enable the the lowresources.mod on the command line, which has the effect of including the following XML configuration:

Unresolved directive in tuning/limit-load.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../jetty-server/src/main/config/etc/jetty-lowresources.xml[]

The monitor is configured with a period in milliseconds at which it will scan the server looking for a low resources condition, which may be one of:

  • If monitorThreads is configured as true and a connectors Executor is an instance of ThreadPool, then its isLowOnThreads() method is used to detect low resources.

  • If maxConnections is configured to a number >0 then if the total number of connections from all monitored connectors exceeds this value, then low resources state is entered.

  • If the maxMemory field is configured to a number of bytes >0 then if the JVMs total memory minus its idle memory exceeds this value, then low resources state is entered.

Once low resources state is detected, then the monitor will iterate over all existing connections and set their IdleTimeout to its configured lowResourcesIdleTimeout in milliseconds. This allows the idle time of existing connections to be reduced so that the connection is quickly closed if no further request are received.

If the low resources state persists longer than the time in milliseconds configured for the maxLowResourcesTime field, the the lowResourcesIdleTimeout is repeatedly applied so that new connections as well as existing connections will be limited.

Jetty Websocket API

These pages are works in progress that have not been moved to their respective sections yet.

Jetty WebSocket Server API

Jetty provides the ability to wire up WebSocket endpoints to Servlet Path Specs via the use of a JettyWebSocketServlet bridge servlet.

Internally, Jetty manages the HTTP Upgrade to WebSocket and migration from a HTTP Connection to a WebSocket Connection.

This will only work when running within the Jetty Container (unlike past Jetty technologies, you cannot get Jetty WebSocket server functionality running Jetty within other containers like JBoss, Tomcat, or WebLogic).

The Jetty WebSocketServlet

To wire up your WebSocket to a specific path via the JettyWebSocketServlet, you will need to extend org.eclipse.jetty.websocket.servlet.JettyWebSocketServlet and specify what WebSocket object should be created with incoming Upgrade requests.

Unresolved directive in websockets/jetty/jetty-websocket-server-api.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java[]

This example will create a Servlet mapped via the @WebServlet annotation to the Servlet path spec of "/echo" (or you can do this manually in the WEB-INF/web.xml of your web application) which will create MyEchoSocket instances when encountering HTTP Upgrade requests.

The JettyWebSocketServlet.configure(JettyWebSocketServletFactory factory) is where you put your specific configuration for your WebSocket. In the example we specify a 10 second idle timeout and register MyEchoSocket with the default JettyWebSocketCreator the WebSocket class we want to be created on Upgrade.

It is important that you take in account any firewall or router timeouts when configuring websockets. Be sure the websocket configuration is lower than your firewall or router.

Using the JettyWebSocketCreator

All WebSocket’s are created via whatever JettyWebSocketCreator you have registered with the JettyWebSocketServletFactory.

By default, the JettyWebSocketServletFactory is a simple JettyWebSocketCreator capable of creating a single WebSocket object. Use JettyWebSocketCreator.register(Class<?> websocket) to tell the JettyWebSocketServletFactory which class it should instantiate (make sure it has a default constructor).

If you have a more complicated creation scenario, you might want to provide your own JettyWebSocketCreator that bases the WebSocket it creates off of information present in the UpgradeRequest object.

Unresolved directive in websockets/jetty/jetty-websocket-server-api.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java[]

Here we show a JettyWebSocketCreator that will utilize the WebSocket subprotocol information from request to determine what WebSocket type should be created.

Unresolved directive in websockets/jetty/jetty-websocket-server-api.adoc - include::/home/runner/work/jetty.project/jetty.project/documentation/jetty-documentation/../jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java[]

When you want a custom JettyWebSocketCreator, use JettyWebSocketServletFactory.setCreator(JettyWebSocketCreator creator) and the JettyWebSocketServletFactory will use your creator for all incoming Upgrade requests on this servlet.

Other uses for a JettyWebSocketCreator:

  • Controlling the selection of WebSocket subprotocol

  • Performing any WebSocket origin you deem important.

  • Obtaining the HTTP headers from incoming request

  • Obtaining the Servlet HttpSession object (if it exists)

  • Specifying a response status code and reason

If you don’t want to accept the upgrade, simply return null from the JettyWebSocketCreator.createWebSocket(UpgradeRequest req, UpgradeResponse resp) method.

Java Websocket API

JSR-356 These pages are works in progress that have not been moved to their respective sections yet.