Configure embedded jetty with web.xml?

29,933

Solution 1

Use a org.eclipse.jetty.webapp.WebAppContext

Example:

package jetty;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;

public class OnWebApp
{
    public static void main(String[] args) throws Exception
    {
        // Create a basic jetty server object that will listen on port 8080.
        // Note that if you set this to port 0 then a randomly available port
        // will be assigned that you can either look in the logs for the port,
        // or programmatically obtain it for use in test cases.
        Server server = new Server(8080);

        // The WebAppContext is the entity that controls the environment in
        // which a web application lives and breathes. In this example the
        // context path is being set to "/" so it is suitable for serving
        // root context requests and then we see it setting the location of
        // the war. A whole host of other configurations are available,
        // ranging from configuring to support annotation scanning in the
        // webapp (through PlusConfiguration) to choosing where the webapp
        // will unpack itself.
        WebAppContext webapp = new WebAppContext();
        webapp.setContextPath("/");
        webapp.setWar("path/to/my/test.war");

        // A WebAppContext is a ContextHandler as well so it needs to be set to
        // the server so it is aware of where to send the appropriate requests.
        server.setHandler(webapp);

        // Start things up! By using the server.join() the server thread will
        // join with the current thread.
        // See http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()
        // for more details.
        server.start();
        server.join();
    }
}

Note that you will build a normal WAR file, and use it with Jetty.

If you have special requirements such as Annotation scanning or JNDI, then you'll need to get into configuration specification.

// Enable parsing of jndi-related parts of web.xml and jetty-env.xml
org.eclipse.jetty.webapp.Configuration.ClassList classlist =
   org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);

// Enable JNDI
classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration",
   "org.eclipse.jetty.plus.webapp.EnvConfiguration",
   "org.eclipse.jetty.plus.webapp.PlusConfiguration");

// Enable Annotation Scanning
classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
  "org.eclipse.jetty.annotations.AnnotationConfiguration");

For a longer example of this in a WebAppContext, see the ServerWithAnnotations example.

Also note that you will have all of the webapp classloader rules in place using this technique as well. Meaning you will have a classloader for the webapp and another one for the server. This is important to understand.

There are a few tweaks you can do to the WebAppContext for classloaders, but you can't eliminate them, just control how they behave.

WebAppContext webapp = new WebAppContext();
// ... various setup of the webapp ...
// Flip the classloader priority from servlet spec where webapp is first to
// Standard java behavior of parent (aka Server classloader) is first.
webapp.setParentLoaderPriority(true);

See also:

Solution 2

I ended up using Joakim's approach, but pointing at the webapp directory instead of the war file.

public static void main(String[] args) throws Exception {
    Server server = new Server(8080);

    String rootPath = SimplestServer.class.getClassLoader().getResource(".").toString();
    WebAppContext webapp = new WebAppContext(rootPath + "../../src/main/webapp", "");
    server.setHandler(webapp);

    server.start();
    server.join();
}
Share:
29,933
Stephan
Author by

Stephan

Software Engineer for Pivotal Labs.

Updated on August 26, 2020

Comments

  • Stephan
    Stephan almost 4 years

    I am trying to generate both a war with my web application as well as a self contained jar file with embedded jetty. For the embedded jetty (the jar file distribution) I add a servlet as follows:

    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
    
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        server.setHandler(context);
    
        context.addServlet(new ServletHolder(new HelloServlet()),"/*");
    
        server.start();
        server.join();
    }
    

    The war file distribution uses a web.xml file that contains the following in the web-app section:

    <servlet>
        <servlet-class>com.example.HelloServlet</servlet-class>
        <servlet-name>SimplestServer</servlet-name>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    

    This works. However, I want to get rid of the duplication between the two approaches. I.e., when I add a new servlet I want to have to configure it in only one location. Can I load and use the web.xml file from the embedded jetty?

  • Stephan
    Stephan over 10 years
    Thanks, Joakim! Using your approach, the only thing I changed is that I am pointing the WebAppContext at the webapp folder. Check out my main method in the answer below.
  • Prashant
    Prashant over 9 years
    Is there a way to set an additional/different init-param on a servlet configuration (i.e. set a working directory). When i list the servlets the webapp has, it shows only the once i add programmatically (I suspect it needs to start first but then it is too late).
  • user2957009
    user2957009 over 4 years
    This was helpful to me. What is going on here is that you already have the classes in your path. If you use a path that includes another copy of /WEB-INF/classes, then you'll get duplicate resource exceptions when using Spring. This solution only adds the missing webapp folder on top of the existing classes you already have loaded. The issue with this is portability. You can't run this outside of a maven folder structure, instead using the compiled artifact.