I am getting the following exception after after reloading an application which uses tag libraries. I am using Tomcat 5.0 nightly build 20030421 with JDK 1.4.2 beta (I believe this will be reproducible on 1.4.1 as well, though). I am attaching only the root cause, not the ServletException which wraps it. Steps to reproduce are below. java.lang.InternalError: jzentry == 0, jzfile = 406263984, total = 4, name = E:\software\tomcat50nightly\webapps\taglibtest\WEB-INF\lib\Test1.jar, i = 3, message = invalid LOC header (bad signature) at java.util.zip.ZipFile$2.nextElement(ZipFile.java:321) at java.util.jar.JarFile$1.nextElement(JarFile.java:211) at org.apache.jasper.compiler.TldLocationsCache.processTldsInJar(TldLocationsCache.java:320) at org.apache.jasper.compiler.TldLocationsCache.processTldsInGlobalJars(TldLocationsCache.java:455) at org.apache.jasper.compiler.TldLocationsCache.init(TldLocationsCache.java:215) at org.apache.jasper.compiler.TldLocationsCache.getLocation(TldLocationsCache.java:188) at org.apache.jasper.JspCompilationContext.getTldLocation(JspCompilationContext.java:557) at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:452) at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:514) at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1562) at org.apache.jasper.compiler.Parser.parse(Parser.java:171) at org.apache.jasper.compiler.ParserController.parse(ParserController.java:248) at org.apache.jasper.compiler.ParserController.parse(ParserController.java:150) at org.apache.jasper.compiler.ParserController.parse(ParserController.java:137) at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:250) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:458) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:444) at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:593) at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:300) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:293) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:240) at javax.servlet.http.HttpServlet.service(HttpServlet.java:853) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:288) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:263) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:151) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:552) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1017) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:196) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:151) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:552) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1017) at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2708) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:186) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:151) at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:149) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:172) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:149) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:552) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1017) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:163) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:151) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:552) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1017) at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:199) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:630) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:463) at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:568) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:631) at java.lang.Thread.run(Thread.java:534) The scenario in which this occurs is basically the following: 1. Create a web application with a tag library and a JSP which uses this taglib 2. Run the application in Tomcat (put it to e.g. webapps/taglibtest) and run the JSP 3. Add a tag to the tag library, use this new tag in the JSP and copy it over to Tomcat again 4. Reload the application using the manager application: http://localhost:8080/manager/reload?path=/taglibtest 5. Run the JSP again This is basically a consequence of JDK bug 4425695/4843994: http://developer.java.sun.com/developer/bugParade/bugs/4843994.html http://developer.java.sun.com/developer/bugParade/bugs/4425695.html I believe it could be fixed by not caching the JarURLConnection in TldLocationsCache.processTldsInJar(...) by setting connection.setUseCaches(false). I am attaching two versions of the web module I tested this with, and steps to reproduce with these: 1. Unzip wm1.zip to webapps/taglibtest 2. Start Tomcat 3. Run http://localhost:8080/taglibtest/UsesTestTL.jsp 4. Unzip wm2.zip to webapps/taglibtest 5. "Touch" the UsesTestTL.jsp file, so Jasper reloads it 6. Reload the application using http://localhost:8080/manager/reload?path=/taglibtest 7. Run http://localhost:8080/taglibtest/UsesTestTL.jsp again The exception is displayed in the browser.
Created attachment 5953 [details] The first version of the test web module
Created attachment 5954 [details] The second version of the test web module
Many file locking issues were fixed, and this should make this kind of webapp update scenario work a lot better. However, I don't see how the scenario you describe could work reliably (on Windows, the JAR could be locked if you try to ovewrite it while the webapp is running). IMO, you should do: - stop webapp - update it - start webapp
Remy, thanks for all the fixes. As for whether this scenario can or can not work - I agree it won't work in 100% of cases. However documentation: http://jakarta.apache.org/tomcat/tomcat-5.0-doc/appdev/source.html http://jakarta.apache.org/tomcat/tomcat-5.0-doc/appdev/processes.html seems to suggest that you should be doing 'compile' and then 'reload'. So do we want to change the documentation to recommend doing 'undeploy', then 'compile' and then 'deploy' ? What should Tomcat recommend to the users so development works reliably and correctly for them ?