Search code examples
javaspringspring-mvctomcatapache-james

Embedded Tomcat in Apache James


I'm trying to enhance the Spring version of the apache-james by adding some ad-hoc actuator @RestControllers.
In order to do so, I was thinking to start an embedded Tomcat 9.x server as a sidecar so that the endpoints can be accessible.

Unfortunately, I get a IllegalStateException: No ServletContext set exception.

The code I've so far is the following:

/**
 * @author cdprete
 * @since 09.06.21
 */
public class EmbeddedTomcat implements DisposableBean {
    private final Tomcat tomcat;

    public EmbeddedTomcat() throws LifecycleException {
        String appBase = ".";
        tomcat = new Tomcat();
        tomcat.getConnector();
        tomcat.getHost().setAppBase(appBase);
        Context context = tomcat.addWebapp("", appBase);
        // Don't scan MANIFESTs, otherwise lots of JARs will be reported as missing
        ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
        tomcat.start();
    }
    @Override
    public void destroy() throws Exception {
        tomcat.destroy();
    }
}
/**
 * @author cdprete
 * @since 08.06.21
 */
@EnableWebMvc
@Configuration
@Import({HealthConfiguration.class, DiskSpaceConfiguration.class, PingConfiguration.class, TraceConfiguration.class})
public class ActuatorConfiguration implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(ActuatorConfiguration.class);
        ctx.setServletContext(servletContext);
        servletContext.addListener(new ContextLoaderListener(ctx));

        ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));

        servlet.setLoadOnStartup(1);
        servlet.addMapping("/");
    }
}

and in the main spring.xml file:

<beans ...>
    ...

    <!-- Embedded Tomcat -->
    <bean class="ch.ti8m.channelsuite.james.actuator.EmbeddedTomcat" />

    <!-- Actuator configuration -->
    <bean class="ch.ti8m.channelsuite.james.actuator.ActuatorConfiguration" />
</beans>

If I start Tomcat from the main method (e.g., like in here), then the web application works as expected (at least the one in the linked example).

What am I missing?


Solution

  • Everything works as expected if the class implementing the WebApplicationInitializer interface is declared before the one having the @EnableWebMvc. In particular, it's not even necessary to add the latter to the context since it's already registered in the context initiated in the WebApplicationInitializer