Search code examples
javatomcat8embedded-tomcat-8

Adding a webApp to Tomcat Embedded dynamically


I need to understand why using the below code to add a webapp dynamically to the embedded tomcat giving the following error, when we add Context on startup everything works fine, the code is the same. Code:

/*
 * Add a context to the host and contexts map; be careful to call this only
 * within a synchronization block of this.contexts
 */
private Context addContextDynamically(String contextPath, String folderName) {
    logger.info("Adding context " + contextPath + " at " + folderName);

    Context contextNew = this.embedded.addWebapp(this.host, contextPath, folderName);
    // Context contextNew = this.embedded.addContext(this.host,contextPath,
    // folderName);
    // this.embedded.addContext(host, contextPath, dir)
    // logger.info("contextNew-->"+contextNew);
    List<File> filterdJarfiles = getAppJarFilesAlone(folderName);
    WebResourceRoot resources = new StandardRoot(contextNew);
    for (File jf : filterdJarfiles) {
        String st = jf.getAbsolutePath().substring(0, jf.getAbsolutePath().lastIndexOf(File.separator));
        logger.info("st-->"+st);
        resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/lib", st, "/"));
    }
    logger.fine("Adding context setResources " + resources);
    logger.fine("Adding context contextNew "+ contextNew);
    logger.fine("Adding context filterdJarfiles " + filterdJarfiles.toString());
    try {
        contexts.put(contextNew.getPath(), contextNew);
        contextNew.setResources(resources);
        INexxWebappLoader loader = new INexxWebappLoader(contextNew.getParentClassLoader(), contextNew);
        contextNew.setLoader(loader);
        // host.addChild(context);
        cleanContextWorkDir((StandardContext) contextNew);

    }catch (Exception e) {
        logger.info("Caught exception while adding context :"+ e.getLocalizedMessage());
        e.printStackTrace();
    }
    return contextNew;
}

The error we get is :

java.lang.IllegalStateException: Error starting static Resources
at org.apache.catalina.core.StandardContext.setResources(StandardContext.java:2470)
at com.medicity.iNexx.AppServer.addContextDynamically(AppServer.java:541)
at com.medicity.iNexx.AppServer.monitorEnablements(AppServer.java:439)
at com.medicity.iNexx.AppServer.run(AppServer.java:345)
at com.medicity.iNexx.AppServer.init(AppServer.java:244)
at com.medicity.iNexx.AppServer.main(AppServer.java:335)

So basically our product downloads the zip and unzip it in the web app directory and in the server.xml we have set:

  <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">

Solution

  • If you add a Context to a running Host, it will be started automatically unless the property startChildren is set to false on the Host component. You probably don't want this, since your addContextDynamically needs to configure the context first.

    Therefore in the method used to configure Tomcat you need to call:

    final Host host = this.embedded.getHost()
    if (host instanceof ContainerBase) {
        ((ContainerBase) host).setStartChildren(false);
    }
    

    and you need to add to addContextDynamically:

    final State hostState = this.embedded.getHost().getState();
    if (hostState.isAvailable() || LifecycleState.STARTING_PREP.equals(hostState)) {
        contextNew.start();
    }
    

    Cf. the source code for more information.

    Remark: Contexts added before the Host starts are immune to the startChildren property.