https://bz.apache.org/bugzilla/show_bug.cgi?id=57772
Bug ID: 57772 Summary: WebappClassLoader throws a ClassNotFoundError when the Manager is deploying a new WAR Product: Tomcat 8 Version: 8.0.20 Hardware: PC OS: Linux Status: NEW Severity: critical Priority: P2 Component: Manager Assignee: dev@tomcat.apache.org Reporter: austinjo...@avadynehealth.com Overview: When contexts are updated through the Tomcat manager interface, ServletContextListener.contextDestroyed implementations which need to load classes throw ClassNotFoundError. Steps to reproduce: 1. Create an instance of Tomcat 8.0.20 2. In server.xml, configure the Host with unpackWARs="true" autoDeploy="false". 3. Check out the example webapp from https://github.com/austinjones/ClassNotFoundGenerator 4. Build the testing WAR using the 'distribute' ant task. 5. Deploy the WAR using an HTTP request to this URL: http://<your-local-tomcat>/manager/text/deploy? war=path/to/workspace/ClassNotFoundGenerator/dist/ClassNotFoundGenerator.war &config=path/to/workspace/ClassNotFoundGenerator/web/context.xml &path=/ClassNotFoundGenerator &update=true 6. Open localhost.log, and verify the ClassNotFoundError was logged. Actual results: The ClassNotFoundError is thrown by TestcaseContextListener.contextDestroyed, and printed to localhost.log. Any further work the context listener was responsible for is not executed. Expected Results: The WebappClassLoader successfully loads classes during ServletContextListener.contextDestroyed, and completes without a throw. No ClassNotFoundError is printed to localhost.log Build Date & Hardware: Tomcat 8.0.12 on CentOS Linux 6.6 Additional Builds and Platforms: Tomcat 8.0.12 on Windows 7 SP1 Tomcat 8.0.20 on Windows 7 SP1 Tomcat 8.0.20 on CentOS Linux 6.6 Note: if you try the 'steps to reproduce' on 8.0.12, the deployment will probably fail due to bug 56398 - which I worked around in 8.0.12. You'll be able to deploy if you change the name of the test app to 'classnotfoundgenerator'. Additional Information: ServletContextListeners that need to load classes during the contextDestroyed call throw ClassNotFoundError, when the application is deployed as a WAR through the Manager interface. Here is an example listener, where ThisClassNotFound is not loaded for the first time in contextDestroyed. https://github.com/austinjones/ClassNotFoundGenerator/blob/master/src/com/avadyne/TestcaseContextListener.java The stack trace of the ClassNotFoundError on 8.0.20 is: 6-Mar-2015 14:38:46.838 SEVERE [http-nio-8443-exec-5] org.apache.catalina.core.StandardContext.listenerStop Exception sending context destroyed event to listener instance of class com.avadyne.TestcaseContextListener java.lang.NoClassDefFoundError: com/avadyne/ThisClassNotFound at com.avadyne.TestcaseContextListener.contextDestroyed(TestcaseContextListener.java:27) at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4775) at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5385) at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232) at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3739) at org.apache.catalina.startup.HostConfig.reload(HostConfig.java:1304) at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1236) at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1491) 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:483) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at org.apache.catalina.manager.ManagerServlet.check(ManagerServlet.java:1460) at org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:906) at org.apache.catalina.manager.ManagerServlet.doGet(ManagerServlet.java:344) at javax.servlet.http.HttpServlet.service(HttpServlet.java:618) at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:108) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:613) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1086) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:659) at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.ClassNotFoundException: com.avadyne.ThisClassNotFound at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1305) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157) ... 45 more The stack trace where Tomcat attempts to load ThisClassNotFound is (8.0.20): Daemon Thread [http-nio-8443-exec-31] (Suspended) owns: WebappClassLoader (id=3483) owns: TestcaseContextListener (id=3488) owns: StandardContext (id=3324) owns: HostConfig (id=3323) owns: SecureNioChannel (id=3313) StandardRoot.getResourceInternal(String, boolean) line: 302 Cache.getResource(String, boolean) line: 65 StandardRoot.getResource(String, boolean, boolean) line: 216 StandardRoot.getClassLoaderResource(String) line: 225 WebappClassLoader(WebappClassLoaderBase).findResourceInternal(String, String) line: 2548 WebappClassLoader(WebappClassLoaderBase).findClassInternal(String) line: 2405 WebappClassLoader(WebappClassLoaderBase).findClass(String) line: 854 WebappClassLoader(WebappClassLoaderBase).loadClass(String, boolean) line: 1274 WebappClassLoader(WebappClassLoaderBase).loadClass(String) line: 1157 TestcaseContextListener.contextDestroyed(ServletContextEvent) line: 27 StandardContext.listenerStop() line: 4775 StandardContext.stopInternal() line: 5385 StandardContext(LifecycleBase).stop() line: 232 StandardContext.reload() line: 3739 HostConfig.reload(HostConfig$DeployedApplication) line: 1304 HostConfig.checkResources(HostConfig$DeployedApplication) line: 1236 HostConfig.check(String) line: 1491 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 Method.invoke(Object, Object...) line: 483 BaseModelMBean.invoke(String, Object[], String[]) line: 300 DefaultMBeanServerInterceptor.invoke(ObjectName, String, Object[], String[]) line: 819 JmxMBeanServer.invoke(ObjectName, String, Object[], String[]) line: 801 ManagerServlet.check(String) line: 1460 ManagerServlet.deploy(PrintWriter, String, ContextName, String, boolean, StringManager) line: 906 ManagerServlet.doGet(HttpServletRequest, HttpServletResponse) line: 344 ManagerServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 618 ManagerServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 725 ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 291 ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 WsFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 52 ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 239 ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 SetCharacterEncodingFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 108 ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 239 ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 StandardWrapperValve.invoke(Request, Response) line: 219 StandardContextValve.invoke(Request, Response) line: 106 BasicAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 613 StandardHostValve.invoke(Request, Response) line: 142 ErrorReportValve.invoke(Request, Response) line: 79 AccessLogValve(AbstractAccessLogValve).invoke(Request, Response) line: 610 StandardEngineValve.invoke(Request, Response) line: 88 CoyoteAdapter.service(Request, Response) line: 516 Http11NioProcessor(AbstractHttp11Processor).process(SocketWrapper<S>) line: 1086 Http11NioProtocol$Http11ConnectionHandler(AbstractProtocol$AbstractConnectionHandler).process(SocketWrapper<S>, SocketStatus) line: 659 Http11NioProtocol$Http11ConnectionHandler.process(SocketWrapper<NioChannel>, SocketStatus) line: 223 NioEndpoint$SocketProcessor.doRun(SelectionKey, NioEndpoint$KeyAttachment) line: 1558 NioEndpoint$SocketProcessor.run() line: 1515 ThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: 1142 ThreadPoolExecutor$Worker.run() line: 617 TaskThread$WrappingRunnable.run() line: 61 TaskThread(Thread).run() line: 745 The ClassLoader gives up on loading the class. The WebResourceSet it would have used to load the class from (in the method StandardRoot.getResourceInternal) is a DirResourceSet pointed to the exploded directory path - e.g. /path/to/tomcat/webapps/ClassNotFoundGenerator/. The path it generates in DirResourceSet.getResource is /path/to/tomcat/webapps/ClassNotFoundGenerator/WEB-INF/classes/com/avadyne/ThisClassNotFound.class - the path is correct. The file doesn't exist, and it returns a new EmptyResource(root, path, f). When the WebappClassLoader attempts to load the class, the .class file (and the entire exploded directory) is not on the disk. The bug occurs during these frames of the ClassNotFoundError stack trace (8.0.20). java.lang.NoClassDefFoundError: com/avadyne/ThisClassNotFound ... at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3739) at org.apache.catalina.startup.HostConfig.reload(HostConfig.java:1304) at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1236) ... HostConfig.checkResources:1231 deletes the exploded directory HostConfig.checkResources:1236 calls into StandardContext.reload StandardContext.reload:3739 eventually invokes the ServletContextListeners Once the contextDestroyed listeners are executed, the .class file doesn't exist (HostConfig.checkResources deleted it). It is unsafe for HostConfig.checkResources to delete the unpacked directory before the context is stopped. However, WebappClassLoader is correct to throw a ClassNotFoundError, since the class doesn't exist on disk. -- You are receiving this mail because: You are the assignee for the bug. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org