Home > Net >  Tomcat 9.0.52 won't load project from the WAR file
Tomcat 9.0.52 won't load project from the WAR file

Time:12-15

I recently upgraded my Tomcat 6 to 9.0.52 by referring to https://blogs.nologin.es/rickyepoderi/index.php?/archives/44-Tomcat-7-and-the-Invoker-Servlet.html

The project is deployed successfully on my local machine however, and I am trying to deploy my project to a remote server but my tomcat throws 'HTTP Status 404 – Not Found' error whenever I try to deploy using a WAR file. However, if I copy over the ROOT folder directly from my local Tomcat or deploy my project using Eclipse the project loads fine.

Here's the localhost.out file:

06-Dec-2021 15:04:21.712 SEVERE [main] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class [test.ctxlistener.InvokerLoadListener]
java.lang.ExceptionInInitializerError
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at test.ctxlistener.InvokerLoadListener.getClasses(Unknown Source)
    at test.ctxlistener.InvokerLoadListener.contextInitialized(Unknown Source)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4768)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5230)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:726)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:698)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:696)
    at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:690)
    at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1889)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
    at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:583)
    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:473)
    at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1618)
    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:319)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123)
    at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:423)
    at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:366)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:946)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:835)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1396)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1386)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:919)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:263)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:432)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:927)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:772)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476)
Caused by: java.lang.NullPointerException
    at java.util.Properties$LineReader.readLine(Properties.java:434)
    at java.util.Properties.load0(Properties.java:353)
    at java.util.Properties.load(Properties.java:341)
    at test.connection.PooledDataSource.<clinit>(Unknown Source)
    ... 45 more

I checked to see if I was using any old/unnecessary .jars but that didn't help. I am using JAVA 8 and Ant 1.10.5.

Also a copy of the error in my catalina.out file is as follows:

06-Dec-2021 15:04:21.712 SEVERE [main] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file 06-Dec-2021 15:04:21.712 SEVERE [main] org.apache.catalina.core.StandardContext.startInternal Context [] startup failed due to previous errors 06-Dec-2021 15:04:21.759 INFO [main] org.apache.catalina.startup.HostConfig.deployDescriptor Deployment of deployment descriptor [C:\Apache-Tomcat\apache-tomcat-9.0.52\conf\Catalina\localhost\ROOT.xml] has finished in [5,703] ms 06-Dec-2021 15:04:21.759 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] 06-Dec-2021 15:04:21.790 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["https-openssl-nio-8443"] 06-Dec-2021 15:04:21.806 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-127.0.0.1-8009"] 06-Dec-2021 15:04:21.806 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [5803] milliseconds

I am not sure what I am missing here. Any help would be greatly appreciated. Thank you!

Here's the source code for invoker :

package test.ctxlistener;
import java.io.File;
import java.net.URL;
import java.util.Enumeration;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;


public class InvokerLoadListener implements ServletContextListener {

    /**
     * Invoker parameter that defines the packages to search servlets.
     * Comma separated list of packages
     */
    public static final String PACKAGES_PARAMETER = "invoker.packages";
    
    /**
     * Invoker parameter to setup the mapping name. By default is "/servlet/"
     */
    public static final String INVOKER_PREFIX_PARAMETER = "invoker.prefix";

    /**
     * Scans all classes accessible from the context class loader which 
     * belong to the given package and subpackages.
     * 
     * @param packageName
     * @return The list of classes found
     */

    private List<Class<?>> getClasses(String packageName)
            throws Exception {
        String path = packageName.replace('.', '/');
        ClassLoader classLoader = Thread.currentThread()
                .getContextClassLoader();
        assert classLoader != null;
        Enumeration<URL> resources = classLoader.getResources(path);
        List<String> dirs = new ArrayList<String>();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(resource.getFile());
        }
        TreeSet<String> classes = new TreeSet<String>();
        for (String directory : dirs) {
            classes.addAll(findClasses(directory, packageName));
        }
        ArrayList<Class<?>> classList = new ArrayList<Class<?>>();
        for (String clazz : classes) {
            classList.add(Class.forName(clazz));
        }

        return classList;
    }


    private  TreeSet<String> findClasses(String directory,
            String packageName) throws Exception {
        TreeSet<String> classes = new TreeSet<String>();
        if (directory.startsWith("file:") && directory.contains("!")) {
            String[] split = directory.split("!");
            URL jar = new URL(split[0]);
            try (ZipInputStream zip = new ZipInputStream(jar.openStream())) {
                ZipEntry entry = null;
                while ((entry = zip.getNextEntry()) != null) {
                    if (entry.getName().endsWith(".class")) {
                        String className = entry.getName()
                                .replaceAll("[$].*", "")
                                .replaceAll("[.]class", "")
                                .replace('/', '.');
                        if (className.startsWith(packageName)) {
                            classes.add(className);
                        }
                    }
                }
            }
        }
        File dir = new File(directory);
        if (!dir.exists()) {
            return classes;
        }
        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    assert !file.getName().contains(".");
                    classes.addAll(findClasses(file.getAbsolutePath(),
                            packageName   "."   file.getName()));
                } else if (file.getName().endsWith(".class")) {
                    classes.add(packageName
                              '.'
                              file.getName().substring(0,
                                    file.getName().length() - 6));
                }
            }
        }

        return classes;
    }

    
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized(ServletContextEvent e)");
        ServletContext sc = sce.getServletContext();
        String list = sc.getInitParameter(PACKAGES_PARAMETER);
        String prefix = sc.getInitParameter(INVOKER_PREFIX_PARAMETER);
        if (prefix == null) {
            prefix = "/servlet/";
        }       
                    
        if (list != null) {
            String[] packages = list.split(",");
            for (int i = 0; i < packages.length; i  ) {
                String packageName = packages[i].trim();
                if (packageName.length() > 0) {
                    // load classes under servlet.invoker
                System.out.println("Checking package: "   packageName);
                    List<Class<?>> classes = null;
                    try {
                        classes = getClasses(packageName);
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    for (Class clazz : classes) {
                        String mapping = prefix   clazz.getName(); 
                        System.out.println(mapping);
                        ServletRegistration sr = sc.getServletRegistration(clazz.getName());
                        if ( sr == null ) {
                            sr = sc.addServlet(clazz.getName(), clazz.getName());}
                        if ( sr != null ) {
                          sr.addMapping(mapping);}
                    }
                }
            }
        }
    }

@Override
public void contextDestroyed(ServletContextEvent sce) {
    System.out.println("contextDestroyed(ServletContextEvent e)");
}
}

CodePudding user response:

Here is one possible answer. As the commenter @piotr-p-karwasz has mentioned, the error is due to a static method failure in test.connection.PooledDataSource. Specifically where it loads a properties file.

at java.util.Properties.load(Properties.java:341)

This is very similar to java.util.Properties$LineReader.readLine

Based on your description that if you copy the entire ROOT folder into the new Tomcat server the app starts up, you should check to see if there is a configuration file (like a *.properties file) in your project and if it is added correctly to your WAR file by the Ant build script. You can do this by unzipping the WAR file in a temp folder and compare the contents with the ROOT folder in your previous Tomcat version.

You will get a more accurate answer when you provide the test.connection.PooledDataSource class source in your question.

  • Related