Bug 18411 - External JAR refresh - caching problem
Summary: External JAR refresh - caching problem
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.0   Edit
Hardware: PC Windows 2000
: P2 normal (vote)
Target Milestone: 2.0 F2   Edit
Assignee: Jerome Lanneluc CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2002-05-31 03:53 EDT by Dani Megert CLA
Modified: 2002-06-03 10:26 EDT (History)
0 users

See Also:


Attachments
p1.zip lib containing X and Y (1.22 KB, application/zip)
2002-05-31 07:49 EDT, Philipe Mulet CLA
no flags Details
p1.zip lib containing only X type (679 bytes, application/zip)
2002-05-31 07:49 EDT, Philipe Mulet CLA
no flags Details
x.jar (112.29 KB, application/zip)
2002-05-31 10:29 EDT, Dani Megert CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dani Megert CLA 2002-05-31 03:53:27 EDT
Build 20020530

Found the bug while testing archive refresh.

0. Import x.jar from external location and add the JAR to the build path
   ==> x.jar as INTERNAL JAR
1. Drill into a package where class C is visible
2. Remove x.jar from build path (not from project)
3. Add x.jar as EXTERNAL JAR
4. Drill into the package where class C is visible
5. Delete C from the external JAR
6. Refresh the project
==> C remains visible

Same scenario works if started with 3.
Comment 1 Philipe Mulet CLA 2002-05-31 06:14:37 EDT
If enabling delta tracing, you'll see that the correct delta got notified.

Java Model[*]: {CHILDREN}
	Proj1[*]: {CHILDREN}
		D:/zz/x.jar[*]: {CONTENT | ARCHIVE CONTENT CHANGED}

However, the package view listener doesn't check for this change, and thus 
doesn't refresh.

I got it to work fine when changing JavaElementContentProvider#processDelta as 
follow (BTW this method would benefit from being rewritten using a switch 
statement):

[	/**
	 * Processes a delta recursively. When more than two children are 
affected the
	 * tree is fully refreshed starting at this node. The delta is 
processed in the
	 * current thread but the viewer updates are posted to the UI thread.
	 */
	protected void processDelta(IJavaElementDelta delta) throws 
JavaModelException {
		int kind= delta.getKind();
		int flags= delta.getFlags();
		IJavaElement element= delta.getElement();

		if (!getProvideWorkingCopy() && isWorkingCopy(element))
			return;

		if (element != null && element.getElementType() == 
IJavaElement.COMPILATION_UNIT && !element.getJavaProject().isOnClasspath
(element))
			return;
			 
		// handle open and closing of a solution or project
		if (((flags & IJavaElementDelta.F_CLOSED) != 0) || ((flags & 
IJavaElementDelta.F_OPENED) != 0)) {			
			postRefresh(element);
			return;
		}

		if (kind == IJavaElementDelta.REMOVED) {
			// when a working copy is removed all we have to do
			// is to refresh the compilation unit
			if (isWorkingCopy(element)) {
				refreshWorkingCopy((IWorkingCopy)element);
				return;
			}
			Object parent= internalGetParent(element);		
	
			postRemove(element);
			if (parent instanceof IPackageFragment) 
				updatePackageIcon((IPackageFragment)parent);
			// we are filtering out empty subpackages, so we
			// a package becomes empty we remove it from the 
viewer. 
			if (isPackageFragmentEmpty(element.getParent())) {
				if (fViewer.testFindItem(parent) != null)
					postRefresh(internalGetParent(parent));
			}  
			return;
		}

		if (kind == IJavaElementDelta.ADDED) { 
			// when a working copy is added all we have to do
			// is to refresh the compilation unit
			if (isWorkingCopy(element)) {
				refreshWorkingCopy((IWorkingCopy)element);
				return;
			}
			Object parent= internalGetParent(element);
			// we are filtering out empty subpackages, so we
			// have to handle additions to them specially. 
			if (parent instanceof IPackageFragment) {
				Object grandparent= internalGetParent(parent);
				// 1GE8SI6: ITPJUI:WIN98 - Rename is not shown 
in Packages View
				// avoid posting a refresh to an unvisible 
parent
				if (parent.equals(fInput)) {
					postRefresh(parent);
				} else {
					// refresh from grandparent if parent 
isn't visible yet
					if (fViewer.testFindItem(parent) == 
null)
						postRefresh(grandparent);
					else {
						postRefresh(parent);
					}	
				}
			} else {  
				postAdd(parent, element);
			}
		}

		if (element instanceof ICompilationUnit) {
			if (getProvideWorkingCopy()) {
				IJavaElement original= ((IWorkingCopy)
element).getOriginalElement();
				if (original != null)
					element= original;
			}
			if (kind == IJavaElementDelta.CHANGED) {
				postRefresh(element);
				return;
			}
		}
		// we don't show the contents of a compilation or IClassFile, 
so don't go any deeper
		if ((element instanceof ICompilationUnit) || (element 
instanceof IClassFile))
			return;
		
		if (isClassPathChange(delta)) {
			 // throw the towel and do a full refresh of the 
affected java project. 
			postRefresh(element.getJavaProject());
		}
		
		if (delta.getResourceDeltas() != null) {
			IResourceDelta[] rd= delta.getResourceDeltas();
			for (int i= 0; i < rd.length; i++) {
				processResourceDelta(rd[i], element);
			}
		}
		if (element instanceof IPackageFragmentRoot 
			&& kind == IJavaElementDelta.CHANGED
			&& flags == (IJavaElementDelta.F_CONTENT | 
IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED)){
			postRefresh(element);
			return;
		}
		
		IJavaElementDelta[] affectedChildren= delta.getAffectedChildren
();
		if (affectedChildren.length > 1) {
			// a package fragment might become non empty refresh 
from the parent
			if (element instanceof IPackageFragment) {
				IJavaElement parent= (IJavaElement)
internalGetParent(element);
				// 1GE8SI6: ITPJUI:WIN98 - Rename is not shown 
in Packages View
				// avoid posting a refresh to an unvisible 
parent
				if (element.equals(fInput)) {
					postRefresh(element);
				} else {
					postRefresh(parent);
				}
				return;
			}
			// more than one child changed, refresh from here 
downwards
			if (element instanceof IPackageFragmentRoot)
				postRefresh(skipProjectPackageFragmentRoot
((IPackageFragmentRoot)element));
			else
				postRefresh(element);
			return;
		}
		for (int i= 0; i < affectedChildren.length; i++) {
			processDelta(affectedChildren[i]);
		}
	}
]

Comment 2 Dani Megert CLA 2002-05-31 06:49:12 EDT
That's what we see too BUT when getting the JAR it seams to return old (cached?)
values.
Comment 3 Philipe Mulet CLA 2002-05-31 07:49:12 EDT
Created attachment 1136 [details]
p1.zip lib containing X and Y
Comment 4 Philipe Mulet CLA 2002-05-31 07:49:56 EDT
Created attachment 1137 [details]
p1.zip lib containing only X type
Comment 5 Philipe Mulet CLA 2002-05-31 07:52:08 EDT
Using attached archives, and if doing precisely:


0. Import p1.zip from external location and add the JAR to the build path
   ==> p1.zip as INTERNAL JAR
1. Drill into a package where class Y is visible
2. Remove p1.zip from build path (not from project)
3. Add p1.zip as EXTERNAL JAR
4. Drill into the package where class Y is visible
5. Switch p1.zip with the one not containing X and Y
6. Refresh the project
==> Y is gone
Comment 6 Erich Gamma CLA 2002-05-31 10:07:56 EDT
dani can you pls try reproduce
Comment 7 Dani Megert CLA 2002-05-31 10:29:03 EDT
I can reproduce it every time (note: I test on what's in JDT HEAD plus newest
jdtcore export from Dirk). I do the steps quickly after each other.

0. Export attached x.jar to c:\
1. Fresh workspace
2. Create Ja project "JUnit"
3. Import x.jar from file system c:\ (as single file)
4. Add x.jar to the build path
5. Open junit.samples.VectorTest
6. Remove x.jar from the build path (press OK)
7. Add external c:\JAR x.jar to the build path
8. Open junit.samples.VectorTest
9. Open c:\x.jar with winzip, delete VectorTest.java, close winzip
10. Select project "JUnit" in packages view press F5
==> VectorTest remains in Packages view
Note: Close the project, reopen it: now VectorTest is gone
Comment 8 Dani Megert CLA 2002-05-31 10:29:29 EDT
Created attachment 1139 [details]
x.jar
Comment 9 Dani Megert CLA 2002-05-31 10:30:40 EDT
Aahh - the main difference is that you switch the zips while I EDIT the external
zip.
Comment 10 Philipe Mulet CLA 2002-05-31 11:59:48 EDT
No the problem is that the external JAR is located in the root folder, and that 
platform API IContainer#findMember("c:/x.jar") may answer the corresponding 
internal JAR instead.

When trying to reproduce, my jar was located in a "c:/zz/x.jar".

Now we found one issue in our code, which was incorrectly calling for for 
IProject.findMember(...) instead of using the root. This is why we did 
misbehave in this one case. So this defect is fixed, but the platform bug 
remains (bug 17209).

Moving to platform/core for further investigation
Comment 11 Jerome Lanneluc CLA 2002-06-03 10:26:40 EDT
Verified