When using Ant to compile JSPs, Jasper locks jar files, so they can not be deleted on Windows. I am attaching an application that reproduces this issue. To use it, do the following: 1. Unpack the zip archive 2. Edit the build.properties file to point to your Tomcat installation (reproduced with 5.0.24) 3. Run ant (reproduced with 1.6.1) in the root directory of the application The ant script compiles pages in the application and then tried to delete the jar files used by the app. Deletion fails.
Created attachment 11640 [details] Test case for this issue
Did you check that it's not an Ant or javac issue ? Do you use fork=true ?
I don't think this is a Javac or Ant issue - in fact, my testcase does not use Javac at all. As I wrote privately to Kin-Man, I believe the problem is that JspC uses URLClassLoader, which is known to lock jar files. When Jasper runs inside the Catalina container, Catalina's WebappClassLoader is used, so the code that locks jars is avoided. But thanks for the hint with fork=true, this actually helped. I replaced the <taskdef name="jasper2" classname="org.apache.jasper.JspC"> style of calling Jasper by the <java> task, which allows to fork JspC: <java classname="org.apache.jasper.JspC" fork="true" failonerror="true" > <arg value="-uriroot"/> <arg value="${basedir}/build/web"/> <arg value="-d"/> <arg value="${basedir}/build/jsps/src"/> <arg value="-die1"/> <classpath> <pathelement location="${java.home}/../lib/tools.jar"/> <fileset dir="${tomcat.home}/bin"> <include name="*.jar"/> </fileset> <fileset dir="${tomcat.home}/server/lib"> <include name="*.jar"/> </fileset> <fileset dir="${tomcat.home}/common/lib"> <include name="*.jar"/> </fileset> </classpath> </java> When using the above code, jar files are not locked and my testcase succeeds. However, I don't much like this solution, because: - Code that uses <java> is uglier than when you use <taskdef> - Tomcat documentation recommends the use of <taskdef>, see: http://jakarta.apache.org/tomcat/tomcat-5.0-doc/jasper-howto.html So I would still appreciate if this is fixed. There is an additional aspect: many current IDEs have some kind of Ant integrations, and most IDEs run Ant internally, without launching a separate process. So when JspC locks jar files, these jar files will be locked until the IDE exits. That's another compelling reason to fix this issue. Thanks.
I'm not sure a fix to URLClassLoader to not lock jar files is that easy, even if it's desirable. However, would adding support for the fork attribute to the JspC task (and maybe even making fork true by default) be good enough?
> I'm not sure a fix to URLClassLoader to not lock jar files is that easy, even > if it's desirable. Agreed. Also, it's desirable to support existing JDKs. Adding fork attribute to JspC would be sufficient, although I'm not sure if it's that easy, because: - You would have to also specify a classpath attribute (or nested element) that would tell the task what classpath to use when the separate JVM is run - You would need to capture output from the separate process and somehow redirect it to the original task's output (Ant output). - You may want to allow all the attributes that the <java> task has that relate to JVM parameters, such as jvm, maxmemory, jvmargs, failonerror, or nested elements jvmarg, sysproperty Is this (easily) doable?
What I had in mind actually was either very simple or complex, depending on how you look at it: have org.apache.jasper.JspC extend org.apache.tools.ant.taskdefs.Java ;) That way we get all the attributes of that task (classpath, jvmargs, sysproperty, forking, etc.) without having to write code for it. We already have the ant.jar in common/lib, so we won't be adding any dependencies. The complex part might be the testing: I don't know the JspC task well enought to comprehensively test it.
Tomcat 5.1 will have an antiLockingResources or antiLockingJARs attribute on the Host or Context that should address this. I'm not sure this will be fixed in Tomcat 5.0.
That would be good, but will the attributes you mention really fix this? JspC does not use any Catalina code at all, and it does not read server.xml, AFAIK. This is purely about Jasper code. How exactly will the new attributes affect this issue? Thanks.
Tomcat 5.5 uses the Eclipse JDT compiler by default, hopefully it behaves better with regards to resource locking.
Yoav, I don't think the usage of JDT will help here, because this is not a Java compiler issue, as I wrote in my comment on 2004-05-25. The problem occurs in the JSP -> servlet translation phase, not in the servlet -> class compilation. Specifically, I believe the problem is in method JspC.initClassLoader(...), which creates a new URLClassLoader. Using a different classloader that does not lock jar files (e.g. WebappClassLoader from Catalina) would fix this issue, IMHO.
This is really getting ridiculous. -1 for adding workarounds to address broken implementation in the JVM. (BTW, I never noticed the behavior you describe) Instead, you should ask your employer to fix *their* bug. Please don't reopen this report.
Remy, I don't understand what's ridiculous about this - this is a legitimate bug. Let's be constructive, please. > -1 for adding workarounds to address broken implementation in the JVM. Doesn't WebappClassLoader already have workarounds to prevent locking jars and to allow redeployment? There is code in Tomcat that bypasses URLConnection, so why apply different measures in this case? Also, I believe Tomcat should strive to work with taday's existing JDKs. FYI, a bug was submitted against JDK, but it was not resolved: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5041014 > BTW, I never noticed the behavior you describe Are you saying you are not able to reproduce this usign the test case I submitted? One practical real-world situation when this may arise is when you run Ant scripts that compile JSPs in IDEs. IDEs generally run Ant in their own VM; they don't launch a separate one. So any jars that are locked by jspc will not be closed after the Ant build completes. Next time you run ant clean (in your IDE), you hit this bug. And here I am not only talking about NetBeans, Eclipse also does it this way, I believe.
I maintain my -1. Fixing this yould be *etremely* painful. The WCL is a different solution, for different needs. There are two workarounds: a) fork your compilation in a separate VM. You should also be able to do that by putting the jspc task in a seprate target, and using a java call to run this target. You acknowledge something similar as a solution, but unfortunately, it is not clean enough for you. This kind of answer does annoy me greatly, as well as your insistence at abusing Yoav's time on this issue which should be handled in the JDK. b) use the Jasper internals, which will allow you to provide your own classloader (which I hope, won't lock JARs).
I agree these are both possible workarounds. However, they are not quite useful for end users of Tomcat: Re. a) This is indeed what we do in NetBeans 4.0. But if we are serious about it, then it should be at least described in http://jakarta.apache.org/tomcat/tomcat-5.5-doc/jasper-howto.html Re. b) An end user of Tomcat is not going to write her own classloader. If we know this would help, why not include and use such a classloader in Jasper directly? That way, ALL users will benefit, not just those who are able and willing to write their own classloader.
-1. BTW, you're definitely not a "regular user", you're embedding Jasper. It's the same when I'm embedding Eclipse JDT (which is a very good compiler) and providing it with a classloader (while I could choose to not care and feed it my classpath using a higher level - and much simpler - interface), because I have specific needs (and this way, since I assume the compiler would lock its JARs, I remain in control of the locking - to some extent: Windows sucks).