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.