26

I am embedding jetty into my app, and trying to work out how to add servlet filters (for cookie handling). The wiki and the javadoc's dont make it very clear, what am I missing:

Server server = new Server(port);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
FilterHolder f = new FilterHolder(new AuthorisationFilter());
context.addFilter(... f ...); // ?????
context.addServlet(new ServletHolder(new TestServlet()), "/");

The only info I have found on this is a forum post suggesting the documentation on this needs to be improved.

Jonas
  • 2,910
  • 2
  • 26
  • 36
Jay
  • 19,649
  • 38
  • 121
  • 184
  • Is there a reason you cannot define it within the web.xml file. I realize this is embedded but as long as you have the file in the classpath under WEB-INF/web.xml you should be fine. – Καrτhικ Jan 18 '13 at 00:45
  • 7
    I've not used web.xml for a long time, normally I just use servlet 3.0 spec annotations. I just don't enjoy mucking around with XML files. – Jay Jan 18 '13 at 04:16

4 Answers4

28

I got the same problem, but I think Καrτhικ's answer is too complex. I found this easy way:

Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/");
context.addFilter(AppFilter.class, "/*", EnumSet.of(DispatcherType.INCLUDE,DispatcherType.REQUEST));

server.setHandler(context);
server.start();
server.join();

My jetty version is 8.1.14.v20131031.

Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
wener
  • 7,191
  • 6
  • 54
  • 78
27

Update: For Jetty version 9.2.2:

    Server server = new Server();

    // Note: if you don't want control over type of connector, etc. you can simply 
    // call new Server(<port>);
    ServerConnector connector = new ServerConnector(server);
    connector.setHost("0.0.0.0");
    connector.setPort(8085);
    // Setting the name allows you to serve different app contexts from different connectors.
    connector.setName("main");
    server.addConnector(connector);

    WebAppContext context = new WebAppContext();
    context.setContextPath("/");
    // For development within an IDE like Eclipse, you can directly point to the web.xml
    context.setWar("src/main/webapp");
    context.addFilter(MyFilter.class, "/", 1);

    HandlerCollection collection = new HandlerCollection();
    RequestLogHandler rlh = new RequestLogHandler();
    // Slf4j - who uses anything else?
    Slf4jRequestLog requestLog = new Slf4jRequestLog();
    requestLog.setExtended(false);
    rlh.setRequestLog(requestLog);
    collection.setHandlers(new Handler[] { context, rlh });
    server.setHandler(collection);

    try {
        server.start();
        server.join();
    } catch (Exception e) {
        // Google guava way
        throw Throwables.propagate(e);
    }

Original answer ===

If you don't want to use web.xml then use this:

SocketConnector socketConnector = new SocketConnector();
socketConnector.setPort(7000); // Change to port you want
Server server.setConnectors(new Connector[] { socketConnector });

WebAppContext webapp = new WebAppContext();

webapp.setContextPath("/"); // For root
webapp.setWar("/"); // Appropriate file system path.

// Now you can use the various webapp.addFilter() methods
webapp.addFilter(MyFilter.class, "/test", 1); // Will serve request to /test.
// There are 3 different addFilter() variants.

// Bonus ... request logs.
RequestLogHandler logHandler = new RequestLogHandler();
NCSARequestLog requestLog = new NCSARequestLog("/tmp/jetty-yyyy_mm_dd.request.log");
requestLog.setRetainDays(90);
requestLog.setAppend(true);
requestLog.setExtended(false);
requestLog.setLogTimeZone("GMT");
logHandler.setRequestLog(requestLog);

logHandler.setHandler(webapp);

HandlerList handlerList = new HandlerList();
handlerList.addHandler(logHandler);

server.setHandler(handlerList);

server.start();

If you do want to use web.xml, instead of the addFilter() methods, just make sure you have a WEB-INF/web.xml in your webapp root path with the following xml:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
   PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
   "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <filter>
        <filter-name>filterName</filter-name>
        <filter-class>com.x.y.z.FilterClass</filter-class>
    </filter>
    <filter-mapping>
        <url-pattern>/test</url-pattern>
        <filter-name>filterName</filter-name>
    </filter-mapping>
</web-app>
Καrτhικ
  • 3,833
  • 2
  • 29
  • 42
  • Thanks. What does the 1 mean in `webapp.addFilter(MyFilter.class, "/test", 1)`. In my code I just ignored it and passed in NULL, that seems to also work. – Jay Jan 20 '13 at 22:44
  • The parameter with a value of 1 is the number of instances to launch at startup. – Καrτhικ Apr 30 '13 at 14:12
  • as I understood jetty 9.1.3, the last parameter is a EnumSet: Declared in ServletContextHandler public FilterHolder addFilter(Class extends Filter> filterClass,String pathSpec,EnumSet dispatches) – Dirk Schumacher Mar 16 '14 at 08:45
  • That's right. In version 9.x lots of api have changed. – Καrτhικ Mar 17 '14 at 21:56
  • can you add multiple filters on same path? – Gobliins Apr 05 '16 at 14:09
  • Here is my implementation. https://imgur.com/a/NKutChB Only the one implementing the Filter class works but not the ContainerRequestFilter. Can you please explain ? – cafebabe1991 Apr 19 '18 at 08:17
  • @cafebabe1991 the filter implementing "ContainerRequestFilter" is a Jersey filter not a Servlet filter like the other. You would need to wire the Jersey filter into the Jersey runtime (which is built on top of Servlets) for it to work. – non sequitor Jun 03 '18 at 22:54
5

The ServletContextHandler.addFilter(...) methods are just convenience wrappers around the ServletHandler.addFilter(...) methods. Provided that you only need one <url-pattern> they are quite convenient. However, if you need more than one pattern or choose to use <servlet-name> instead, you will need something more like this:

ServletContextHandler context = new ServletContextHandler(
        ServletContextHandler.SESSIONS);

FilterMapping mapping = new FilterMapping();
mapping.setFilterName( "Foobar Filter" );
mapping.setPathSpecs( new String[] { "/foo/*", "/bar/*" } );
mapping.setServletNames( new String[] { "foobar" } );
mapping.setDispatcherTypes(
        EnumSet.of( DispatcherType.INCLUDE,DispatcherType.REQUEST ) ) );

FilterHolder holder = new FilterHolder( FoobarFilter.class );
holder.setName( "Foobar Filter" );

context .getServletHandler().addFilter( holder, mapping );
Lucas
  • 14,227
  • 9
  • 74
  • 124
0

Updated for java 11 instead of javax. use jakarta. and 11.0.3 for jetty

ServletHolder servletHolder = new ServletHolder(DefaultServlet.class);
servletHolder.setInitParameter("resourceBase","./resource");
servletHolder.setInitParameter("dirAllowed", "false");
servletHolder.setInitParameter("pathInfoOnly", "true");
servletHandler.addServlet(servletHolder, "/api/source/*");
FilterHolder f = new FilterHolder(new MyFilter());
servletHandler.addFilter(MediaFilter.class, "/api/source/*",     
EnumSet.allOf(DispatcherType.class));
m4n0
  • 29,823
  • 27
  • 76
  • 89