Overview

Fine tuning embedded jetty inside of spark framework.

No Comments

Tech is easy when complexity is hidden away. Hiding complexity means some things are either unreachable anymore or at least hard to reach. One example of easy tech is the spark framework (not to confuse with Apache Spark). Spark lets you build HTTP-services with literally minimal code. The following one-line example is a typical starting point of a application using spark:

import static spark.Spark.get;
 
public class HelloWorld {
    public static void main(String[] args) {
        get("/hello", (req, res) -> "Hello World");
    }
}

Spark deals with most of your http-related need in a similar concise way. Its features are well documented, except when you need to access the hidden complexity I have been talking about. One such feature I consider hidden complexity of spark is its embedded jetty server. In most cases you won’t even notice your are running on top of jetty when using spark. But then there are those rare cases, where you need to change the default configuration for jetty used by spark. Thats where you use the EmbeddedServers class to construct a custom instance of jetty. It is not so well documented (as of time of writing at least), but the example below should give you a good starting point.

For example changing the name of cookie holding the session id form JSESSIONID to something else is done like this:

public class Main {
    public static void main(String ...args) throws Exception {
        EmbeddedServers.add(EmbeddedServers.Identifiers.JETTY, (Routes routeMatcher, StaticFilesConfiguration staticFilesConfiguration, boolean hasMultipleHandler) -> {
            JettyHandler handler = setupHandler(routeMatcher, staticFilesConfiguration, hasMultipleHandler);
            handler.getSessionCookieConfig().setName("XSESSION");
            return new EmbeddedJettyServer((int maxThreads, int minThreads, int threadTimeoutMillis) -> new Server(), handler);
        });
 
        get("/hello", (req, res) -> {
            req.session(true);
            return "Hello World";
        });
    }
 
    /**
     * setup handler in the same manner spark does in {@code EmbeddedJettyFactory.create()}.
     *
     * @see <a href="https://github.com/perwendel/spark/blob/master/src/main/java/spark/embeddedserver/jetty/EmbeddedJettyFactory.java#L39">EmbeddedJettyFactory.java</a>
     */
    private static JettyHandler setupHandler(Routes routeMatcher, StaticFilesConfiguration staticFilesConfiguration, boolean hasMultipleHandler) {
        MatcherFilter matcherFilter = new MatcherFilter(routeMatcher, staticFilesConfiguration, false, hasMultipleHandler);
        matcherFilter.init(null);
 
        return new JettyHandler(matcherFilter);
    }
}

You construct a custom instance of jetty using its api. This is where you leave the “easy tech” land, but jetty and spark provide you with enough well thought out default values so you never feel overwhelmed by the amount of code you have to write. In the example a instance of jetty is constructed in the same way spark does it by default (i.e. MatcherFilter + JettyHandler). I only added the line where the name of session-id holding cookie is changed to XSESSION. This way I do not break functionality provided by spark (routing, filtering, etc.).

Final words.

As usual with spark you must pay attention to order in which you configure spark and setup your routing. Calls to EmbeddedServers.add() must take place before calling Spark.get() for the first time. Once Spark.get() or any other method related to routing is called the lazy initialization kicks in and spark looks for the server constructing factory you have not provided yet.

Comment

Your email address will not be published. Required fields are marked *