Search code examples
jettyembedded-jettyjetty-9

Embedding Jetty 9.3 with modular XmlConfiguration


I am migrating from Jetty 8.1.17 to Jetty 9.3.9. Our application embeds Jetty. Previously we had a single XML configuration file jetty.xml which contained everything we needed.

I felt that with Jetty 9.3.9 it would be much nicer to use the modular approach that they suggest, so far I have jetty.xml, jetty-http.xml, jetty-https.xml and jetty-ssl.xml in my $JETTY_HOME/etc; these are pretty much copies of those from the 9.3.9 distribution. This seems to work well when I use start.jar but not through my own code which embeds Jetty.

Ideally I would like to be able to scan for any jetty xml files in the $JETTY_HOME/etc folder and load the configuration. However for embedded mode I have not found a way to do that without explicitly defining the order that those files should be loaded in, due to <ref id="x"/> dependencies between them etc.

My initial attempt is based on How can I programmatically start a jetty server with multiple configuration files? and looks like:

final List<Object> configuredObjects = new ArrayList();
XmlConfiguration last = null;
for(final Path confFile : configFiles) {
    logger.info("[loading jetty configuration : {}]", confFile.toString());
    try(final InputStream is = Files.newInputStream(confFile)) {
        final XmlConfiguration configuration = new XmlConfiguration(is);
        if (last != null) {
            configuration.getIdMap().putAll(last.getIdMap());
        }
        configuredObjects.add(configuration.configure());
        last = configuration;
    }
}

Server server = null;
// For all objects created by XmlConfigurations, start them if they are lifecycles.
for (final Object configuredObject : configuredObjects) {
    if(configuredObject instanceof Server) {
        server = (Server)configuredObject;
    }

    if (configuredObject instanceof LifeCycle) {
        final LifeCycle lc = (LifeCycle)configuredObject;
        if (!lc.isRunning()) {
            lc.start();
        }
    }
}

However, I get Exceptions at startup if jetty-https.xml is loaded before jetty-ssl.xml or if I place a reference in jetty.xml to an object from a sub-configuration jetty-blah.xml which has not been loaded first.

It seems to me like Jetty manages to do this okay itself when you call java -jar start.jar, so what am I missing to get Jetty to not care about what order the config files are parsed in?


Solution

  • Order is extremely important when loading the Jetty XML files.

    That's the heart of what the entire start.jar and its module system is about, have an appropriate set of properties, the server classpath is sane, and ensuring proper load order of the XML.

    Note: its not possible to have everything in ${jetty.home}/etc loaded at the same time, as you will get conflicts on alternate implementations of common technologies (something start.jar also manages for you)