Bug 78128 - Error deleting project with jar file referenced by other project
Summary: Error deleting project with jar file referenced by other project
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.0   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.0.2   Edit
Assignee: Jerome Lanneluc CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-11-08 18:04 EST by David Slubicki CLA
Modified: 2005-03-10 05:35 EST (History)
4 users (show)

See Also:


Attachments
Patch against 2.1.3 (1.01 KB, patch)
2004-11-18 12:39 EST, Jerome Lanneluc CLA
no flags Details | Diff
For convenience, this is the full source for ToolFactory.java after applying the patch on 2.1.3 (11.46 KB, application/octet-stream)
2004-11-18 12:44 EST, Jerome Lanneluc CLA
no flags Details
Apply after the first patch has been applied (1.48 KB, patch)
2004-11-18 16:48 EST, Olivier Thomann CLA
no flags Details | Diff
For convenience, this is the full source for ToolFactory.java after applying the 2 patches on 2.1.3 (11.60 KB, application/octet-stream)
2004-11-19 05:12 EST, Jerome Lanneluc CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description David Slubicki CLA 2004-11-08 18:04:34 EST
This problem was found using eclipse 2.1.3 but also exists in 3.0.  This 
problem doesn't occur all the time, but below I will provide a way to reproduce 
this problem fairly consistently.  I will also provide a fix (one line).

Problem:

I have java project "X" which contains a jar file (my jar file is named 
log4j.jar).  I have another java project "Y" which has X's jar file on its 
build path.  Occassionally, when I try to delete X (specifying to "delete 
contents..."), I will get a "Delete Problems" dialog that reads:

    title:  Problems encountered while deleting resources.
    details:  Could not delete: /X.
              Could not delete: D:\dev\workspace\X\log4j.jar

If this error occurs I usually have to close/re-open my workspace in order to 
delete the project.

How to reproduce:

I come across this problem in more likely scenarios, but to reproduce this 
problem fairly consistently I just double click on the jar file (in Y) to 
expand it and then quickly double click various packages to expand/collapse 
them and double click various class files to open editors, then close them, 
build the project, right click the project and go to the properties page - go 
to the "Libraries" tab of the Java Build Path page and click OK (mix up these 
steps - open some editors, build, close editors, etc.).  Doing this for less 
than a minute should get you in a state to reproduce the problem.

For a more exact approach, you can track the number of times a 
java.util.zip.ZipFile object is created (with your jar file as the File 
parameter in the constructor) vs. the number of times ZipFile.close() is called 
(again, on a zip file representing your jar file) and wait for the number of 
creations to get well ahead (>5) of the number of times it is closed before you 
try to delete the project.  If needed I can detail a fairly easy way to do this 
by modifying your rt.jar and replacing System.out with a custom PrintStream 
class.

Cause:

Zipfile.close() isn't being called explicitly - it appears that we're allowing 
garbage collection to take care of this.  When we get to 
org.eclipse.ui.actions.DeleteResourceAction.delete(IResource[], 
IProgressMonitor) (after following the steps above and trying to delete the 
project in question) - garbage collection hasn't cleaned up these unreferenced 
ZipFile objects.  

Proposed fix:

Making "System.gc();" the first line of the method:  
org.eclipse.ui.actions.DeleteResourceAction.delete(IResource[], 
IProgressMonitor) fixes this problem.
Comment 1 Kim Horne CLA 2004-11-10 09:21:23 EST
Relying on the behaviour of System.gc() isn't a good idea - it's implementation
specific and is spec'd to only really be a suggestion to the VM.  Calling
close() on the zipfile seems to be a much better idea.  Passing to JDT.
Comment 2 Philipe Mulet CLA 2004-11-16 15:29:26 EST
One known scenario for this to occur is when the Java indexing is busy
processing the offending file. You may reveal its activity by toggling the
progress view in verbose mode.

Can you then tell us whether the indexer is at work when this occurs ?
Comment 3 David Slubicki CLA 2004-11-16 16:38:31 EST
When I tested this I made sure nothing was showing in the Progress status area 
(bottom right hand corner).  I would normally try the deletion soon after 
following the steps I mentioned, but after any tasks (i.e. builds, etc.) were 
complete.  After it failed once I tried waiting a long time (maybe 30 minutes) 
then attempted to delete again - and received the same error.
Comment 4 Jerome Lanneluc CLA 2004-11-18 10:39:11 EST
I looked at our code and indeed I found one occurence where we create a ZipFile
without closing it. This happens when opening a .class file that doesn't have
any source attached. This is the only occurence though.

David, do you see this problem if you open .class files that have source attached?
If you see the problem only when opening .class files that don't have source
attached, then the fix is easy and I can provide you with a patch so that you
can try out. Please let me know wich Eclipse version you would like this patch
to be compatible with (2.1.3 or 3.0.1 ?).
Comment 5 Troy Bishop CLA 2004-11-18 12:18:50 EST
Hi Jerome,

I can't say if the scenario you described is the same as what David was able to
reproduce (I was able to reproduce it once but I do not remember viewing the
class file with no source attached - I could be wrong though), but the patch
would need to be against the v2.1.3 release.  Thanks!
Comment 6 Jerome Lanneluc CLA 2004-11-18 12:39:21 EST
Created attachment 15973 [details]
Patch against 2.1.3
Comment 7 Jerome Lanneluc CLA 2004-11-18 12:41:53 EST
A full JDT Core patch can be found at
http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/jdt-core-home/r2.1/main.html#updates
Comment 8 Jerome Lanneluc CLA 2004-11-18 12:44:33 EST
Created attachment 15974 [details]
For convenience, this is the full source for ToolFactory.java after applying the patch on 2.1.3
Comment 9 Jerome Lanneluc CLA 2004-11-18 12:50:04 EST
Released fix to HEAD, 3.1 maintenance and 2.1 maintenance streams.
Added regression test DeleteTests#testDeleteProjectAfterUsingJar() to HEAD.
Comment 10 Troy Bishop CLA 2004-11-18 13:50:00 EST
I just had a quick question regarding the ToolFactory code that you posted... In
the createDefaultClassFileReader(String zipFileName, String zipEntryName, int
decodingFlag) method, shouldn't there be a call to do zipFile.close() before
returning null in the if(!zipEntryName.toLowerCase().endsWith(".class")) {}
statement as well as after the Util.getZipEntryByteContent(zipEntry, zipFile)
statement?

For example,

public static IClassFileReader createDefaultClassFileReader(String zipFileName,
String zipEntryName, int decodingFlag){
	try {
		if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
			System.out.println("(" + Thread.currentThread() + ")
[ToolFactory.createDefaultClassFileReader()] Creating ZipFile on " +
zipFileName); //$NON-NLS-1$	//$NON-NLS-2$
		}
		ZipFile zipFile = new ZipFile(zipFileName);
		ZipEntry zipEntry = zipFile.getEntry(zipEntryName);
		if (zipEntry == null) {
			return null;
		}
		if (!zipEntryName.toLowerCase().endsWith(".class")) {//$NON-NLS-1$
			zipFile.close(); // <-- close here ?
			return null;
		}
		byte classFileBytes[] = Util.getZipEntryByteContent(zipEntry, zipFile);
		zipFile.close(); // <-- close here ?
		return new ClassFileReader(classFileBytes, decodingFlag);
		} catch(ClassFormatException e) {
			return null;
		} catch(IOException e) {
			return null;
		}
	}
}

I don't know if this would affect this bug but I just wanted to question it
first :) Thanks!
Comment 11 Troy Bishop CLA 2004-11-18 14:08:23 EST
I tested the fix posted and it did not resolve the reported problem.
Comment 12 Olivier Thomann CLA 2004-11-18 15:42:54 EST
I would rather write it like this:
	public static IClassFileReader createDefaultClassFileReader(
		String zipFileName,
		String zipEntryName,
		int decodingFlag) {
		ZipFile zipFile = null;
		try {
			if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
				System.out.println("(" + Thread.currentThread() + ")
[ToolFactory.createDefaultClassFileReader()] Creating ZipFile on " +
zipFileName); //$NON-NLS-1$	//$NON-NLS-2$
			}
			zipFile = new ZipFile(zipFileName);
			ZipEntry zipEntry = zipFile.getEntry(zipEntryName);
			if (zipEntry == null) {
				return null;
			}
			if (!zipEntryName.toLowerCase().endsWith(".class")) { //$NON-NLS-1$
				return null;
			}
			byte classFileBytes[] = Util.getZipEntryByteContent(zipEntry, zipFile);
			return new ClassFileReader(classFileBytes, decodingFlag);
		} catch (ClassFormatException e) {
			return null;
		} catch (IOException e) {
			return null;
		} finally {
			if (zipFile != null) {
				try {
					zipFile.close();
				} catch (IOException e) {
					// ignore
				}
			}
		}
	}

Using a finally block covers all returns statement within the method. This is
indeed what we have done in the 3.0 stream.
Comment 13 Olivier Thomann CLA 2004-11-18 16:48:48 EST
Created attachment 15991 [details]
Apply after the first patch has been applied
Comment 14 Troy Bishop CLA 2004-11-18 17:10:19 EST
The code in comment 12 is much better than what I had posted in comment 10.  I
tested the latest jdt.core update produced by Olivier and I can no longer
reproduce the problem where JAR files are locked so it looks like this problem
is resolved.  Thank you very much!
Comment 15 Jerome Lanneluc CLA 2004-11-19 05:08:23 EST
It looks like I missed one case in the 2.1 stream. So thanks Troy for
identifying that, and thanks Olivier for the fix.
Comment 16 Jerome Lanneluc CLA 2004-11-19 05:12:18 EST
Created attachment 16011 [details]
For convenience, this is the full source for ToolFactory.java after applying the 2 patches on 2.1.3
Comment 17 Jerome Lanneluc CLA 2004-11-19 05:25:44 EST
Comment 14 indicates that the problem is fixed with the 2 patches. Marking as FIXED.
Comment 18 Jerome Lanneluc CLA 2005-01-26 13:08:53 EST
Candidating fix for 3.0.2 release (not committed yet)

Once this is ported to R3_0_maintenance stream, the Target Milestone should be
set back to 2.1.3
Comment 19 Frederic Fusier CLA 2005-03-10 05:35:08 EST
Verified for 3.0.2 with build M200502161722