mjs
mjs

Reputation: 22379

Embedded Tomcat, how to replace existing web.xml meant for standard Tomcat with new logic for Embedded Tomcat

Given existing web.xml:

<?xml version="1.0" encoding="UTF-8"?>

<display-name>/</display-name>

<listener><listener-class>m.Web.startup.Listener</listener-class></listener>
<listener><listener-class>m.Store.Listener</listener-class></listener>

<session-config>
    <session-timeout>30</session-timeout>
</session-config>                                          

<servlet-mapping>
    <servlet-name>mmm.com.dispatcher.servlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
    <servlet-name>mmm.com.dispatcher.servlet</servlet-name>
    <servlet-class>m.Web.startup.DispatcherServlet</servlet-class>
    
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.XmlWebApplicationContext</param-value>
    </init-param>
    
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:/Web/config/ConfigWeb.xml
            classpath:/Auth/config/ConfigAuth.xml
            classpath:/Assets/config/ConfigAssets.xml
            classpath:/Accounts/config/ConfigAccounts.xml
            classpath:/App/config/ConfigApp.xml
            classpath:/Accounts/config/ConfigAccounts.xml
            classpath:/Store/config/ConfigStore.xml
        </param-value>
    </init-param>
    
    <load-on-startup>1</load-on-startup>
</servlet>

I've added:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-core</artifactId>
    <version>8.0.48</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <version>8.0.48</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-logging-juli</artifactId>
    <version>8.0.48</version>
</dependency>

and attempted to do:

private static void c() throws LifecycleException {
    File tmpDir = new File(System.getProperty("java.io.tmpdir"));

    Tomcat tomcat = new Tomcat();
    tomcat.setBaseDir(tmpDir.getAbsolutePath());
    tomcat.setPort(8080);
    
    XmlWebApplicationContext context = new XmlWebApplicationContext();
    
    DispatcherServlet servlet = new DispatcherServlet(context);
    
    servlet.setContextConfigLocation("""
        classpath:/Web/config/ConfigWeb.xml
        classpath:/Auth/config/ConfigAuth.xml
        classpath:/Assets/config/ConfigAssets.xml
        classpath:/Accounts/config/ConfigAccounts.xml
        classpath:/App/config/ConfigApp.xml
        classpath:/Accounts/config/ConfigAccounts.xml
        classpath:/Store/config/ConfigStore.xml
    """);
    
    Tomcat.addServlet(tomcat.addContext(tomcat.getHost(), "/", tmpDir.getAbsolutePath()), "mmm.com.dispatcher.servlet", servlet);

    new m.Web.startup.Listener();
    new m.Store.Listener();
    
    tomcat.start();
    
    tomcat.getServer().await();
}

But is not working.

The server starts but several things are not working. localhost:8080 results in an error page.

Also tried:

public static void e() throws LifecycleException {
    Tomcat tomcat = new Tomcat() {
        @Override
        public Context addWebapp(String contextPath, String docBase) throws ServletException {
            Context context = null;
            try {
                context = new StandardContext();
                context.setName(contextPath);
                context.setPath(contextPath);
                context.setDocBase(docBase);
                context.setRealm(this.getHost().getRealm());
                ContextConfig contextConfig = new ContextConfig();
                context.addLifecycleListener(contextConfig);
                String pathToWebXml = docBase + "Store/web.xml";
                if (new File(pathToWebXml).exists()) {
                    contextConfig.setDefaultWebXml(pathToWebXml);
                } else {
                    contextConfig.setDefaultWebXml("org/apache/catalin/startup/NO_DEFAULT_XML");
                }
                host.addChild(context);
            } catch (Exception e) {
                log.error("Error deploying webapp", e);
            }
            return context;
            
        }
    };
    tomcat.setPort(8081);
    
    Service service = tomcat.getService();
    service.addConnector(sslConnector());
    
    try {
        URL resource = TomcatServer.class.getClassLoader().getResource(".");
        
        tomcat.addWebapp("", resource.getPath());
        //add others here...
    } catch (ServletException e) {
        log.error("Problem webapp. Could be fatal?");
    }
    
    tomcat.start();
    tomcat.getServer().await();
    
}

But this results in errors such as :

WARNING: Failed to scan 

[file:/Users/j/.m2/repository/xalan/xalan/2.7.2/xercesImpl.jar] from classloader hierarchy
java.io.IOException: java.lang.reflect.InvocationTargetException
    at org.apache.tomcat.util.compat.Jre9Compat.jarFileNewInstance(Jre9Compat.java:185)
    at org.apache.tomcat.util.scan.JarFileUrlJar.<init>(JarFileUrlJar.java:65)
    at org.apache.tomcat.util.scan.JarFactory.newInstance(JarFactory.java:49)
    at org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.java:374)
    at org.apache.tomcat.util.scan.StandardJarScanner.processURLs(StandardJarScanner.java:309)
    at org.apache.tomcat.util.scan.StandardJarScanner.doScanClassPath(StandardJarScanner.java:278)
    at org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java:229)
    at org.apache.catalina.startup.ContextConfig.processJarsForWebFragments(ContextConfig.java:1898)
    at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1131)
    at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:783)
    at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:307)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:95)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5212)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
    at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.GeneratedConstructorAccessor6.newInstance(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
    at org.apache.tomcat.util.compat.Jre9Compat.jarFileNewInstance(Jre9Compat.java:182)
    ... 21 more
Caused by: java.nio.file.NoSuchFileException: /Users/j/.m2/repository/xalan/xalan/2.7.2/xercesImpl.jar
    at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
    at java.base/sun.nio.fs.UnixFileAttributeViews$Basic.readAttributes(UnixFileAttributeViews.java:55)
    at java.base/sun.nio.fs.UnixFileSystemProvider.readAttributes(UnixFileSystemProvider.java:148)
    at java.base/java.nio.file.Files.readAttributes(Files.java:1843)
    at java.base/java.util.zip.ZipFile$Source.get(ZipFile.java:1198)
    at java.base/java.util.zip.ZipFile$CleanableResource.<init>(ZipFile.java:701)
    at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:240)
    at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:171)
    at java.base/java.util.jar.JarFile.<init>(JarFile.java:347)
    ... 26 more

Jun 23, 2021 2:57:15 PM org.apache.tomcat.util.scan.StandardJarScanner processURLs
WARNING: Failed to scan [file:/Users/j/.m2/repository/xalan/xalan/2.7.2/xml-apis.jar] from classloader hierarchy
java.io.IOException: java.lang.reflect.InvocationTargetException
    at org.apache.tomcat.util.compat.Jre9Compat.jarFileNewInstance(Jre9Compat.java:185)
    at org.apache.tomcat.util.scan.JarFileUrlJar.<init>(JarFileUrlJar.java:65)
    at org.apache.tomcat.util.scan.JarFactory.newInstance(JarFactory.java:49)
    at org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.java:374)
    at org.apache.tomcat.util.scan.StandardJarScanner.processURLs(StandardJarScanner.java:309)
    at org.apache.tomcat.util.scan.StandardJarScanner.doScanClassPath(StandardJarScanner.java:278)
    at org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java:229)
    at org.apache.catalina.startup.ContextConfig.processJarsForWebFragments(ContextConfig.java:1898)
    at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1131)
    at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:783)
    at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:307)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:95)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5212)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
    at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.GeneratedConstructorAccessor6.newInstance(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
    at org.apache.tomcat.util.compat.Jre9Compat.jarFileNewInstance(Jre9Compat.java:182)
    ... 21 more
Caused by: java.nio.file.NoSuchFileException: /Users/j/.m2/repository/xalan/xalan/2.7.2/xml-apis.jar
    at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
    at java.base/sun.nio.fs.UnixFileAttributeViews$Basic.readAttributes(UnixFileAttributeViews.java:55)
    at java.base/sun.nio.fs.UnixFileSystemProvider.readAttributes(UnixFileSystemProvider.java:148)
    at java.base/java.nio.file.Files.readAttributes(Files.java:1843)
    at java.base/java.util.zip.ZipFile$Source.get(ZipFile.java:1198)
    at java.base/java.util.zip.ZipFile$CleanableResource.<init>(ZipFile.java:701)
    at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:240)
    at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:171)
    at java.base/java.util.jar.JarFile.<init>(JarFile.java:347)
    ... 26 more

Note that currently I am starting it from within a static void main from within Intellij.

The method e() here relies on parsing the existing web.xml file, but this is not working and it fails it seems due to lacking classpath stuff.

The first method c() relies on trying to replicate the configuration, but I am missing ways of trying to properly replicating it.

I am unable for instance to add a Listener in the same manner, and I am unable to configure for instance the session-config parameter.

The first one has no classpath issues and starts but I think some things like the listeners are not properly set up, nor their events fired.

EDIT 1:

Perhaps this the way to add listeners, in c():

 Context ctx = tomcat.addContext(tomcat.getHost(), "/", tmpDir.getAbsolutePath());
    ctx.addApplicationListener(m.Web.startup.Listener.class.getCanonicalName());
    ctx.addApplicationListener(m.Store.Listener.class.getCanonicalName());

But again things start up, but still error in tomcat. Unsure if the classpath: ... in original web.xml mimicked in c() are accurately applied as well.

EDIT 2:

Now gotten most things up, however WebSockets (annotated in the code) is not being picked up, as well as HttpSessionListener not being triggered.

In web.xml you could define a listener that implemented several interfaces such as ServletContextListener, HttpSessionListener but with embedded Tomcat this does not seem to work. I am also not able to register them separately either as of now, but that should be possible. Still annoying.

I just wish you could just feed it the web.xml and it could configure itself, just like the standalone one does. I don't get why that has to be so hard.

private static void c() throws LifecycleException, ServletException, URISyntaxException, DeploymentException, IOException {
    File tmpDir = new File(System.getProperty("java.io.tmpdir"));
                                            
    Tomcat tomcat = new Tomcat();
    tomcat.setBaseDir(tmpDir.getAbsolutePath());
    tomcat.setPort(8080);
    
    Context ctx = tomcat.addContext("", new File(".").getAbsolutePath());
    ctx.addApplicationListener(m.Web.startup.Listener.class.getCanonicalName());
    ctx.addApplicationListener(m.Store.Listener.class.getCanonicalName());
    ctx.addApplicationListener(Listener.class.getCanonicalName());
    ctx.setSessionTimeout(30);
    
    Wrapper wrapper = Tomcat.addServlet(ctx, "mmm.com.dispatcher.servlet", m.Web.startup.DispatcherServlet.class.getCanonicalName());
    
    wrapper.addInitParameter("contextClass", org.springframework.web.context.support.XmlWebApplicationContext.class.getCanonicalName());
    wrapper.addInitParameter("contextConfigLocation", """
        classpath:/Web/config/ConfigWeb.xml
        classpath:/Auth/config/ConfigAuth.xml
        classpath:/Assets/config/ConfigAssets.xml
        classpath:/Accounts/config/ConfigAccounts.xml
        classpath:/App/config/ConfigApp.xml
        classpath:/Accounts/config/ConfigAccounts.xml
        classpath:/Store/config/ConfigStore.xml
    """);
    
    wrapper.setLoadOnStartup(1);
    
    if ( true ) {
        wrapper.addMapping("/");
    }
    else if ( false ) {
        ctx.addServletMappingDecoded("/", "mmm.com.dispatcher.servlet", true);
    }
    
    tomcat.start();

    if ( false ) {
        ContainerProvider.getWebSocketContainer().connectToServer(Socket.class, new URI("ws://"));
    }
    
    tomcat.getServer().await();
}

Upvotes: 0

Views: 1253

Answers (0)

Related Questions