Bug 218583

Summary: Dynamic classpath container contents are not being processed
Product: [Eclipse Project] JDT Reporter: James Leone <jleone>
Component: CoreAssignee: Jerome Lanneluc <jerome_lanneluc>
Status: VERIFIED INVALID QA Contact:
Severity: normal    
Priority: P3 CC: david_audel, philippe_mulet
Version: 3.3.1   
Target Milestone: 3.4 M6   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Attachments:
Description Flags
Simplified plugin with a classpath container and sample projects using that container none

Description James Leone CLA 2008-02-11 20:16:51 EST
Created attachment 89473 [details]
Simplified plugin with a classpath container and sample projects using that container

Build ID: 3.3.1.1 M20071023-1652

Steps To Reproduce:
1. Create a classpathInitializer plugin that has a customer classpath container.
2. Have that container conditionally toggle between a project or a JAR of the project depending on what is open in the workspace
3. Test out the plugin.  See that when the contents of the customer classpath container are expanded everything look good.  If ProjectB is open, the project is referenced.  If ProjectB is closed, the JAR version of ProjectB is in the classpath instead.
4. Close ProjectB and try to build ProjectA
5. Get an error "The project was not build due to 'Resource /ProjectB' is not open"  However, the classpath container is not reference ProjectB, it is referencing the JAR.


More information:
This is being posted per the request in newsgroups
http://www.eclipse.org/newsportal/article.php?id=22236&group=eclipse.tools.jdt#22236

I am including a stripped down version of this type of plugin to server as an example.  Included in that is another jar that has ProjectA which depends on ProjectB (or B.jar if ProjectB is closed).
Comment 1 Jerome Lanneluc CLA 2008-02-25 06:07:25 EST
The problem comes from the fact that the JDT infrastructure is not notified that the classpath entries of the container have changed. The confusion comes from the fact that the UI always shows the latest classpath entries, but the infrastructure (for performance reasons) uses the classpath entries set by the last call to JavaCore#setClasspathContainer(...).

To solve this problem, you should do as the "Plug-in Dependencies" does. I.e. register a pre-processing-resource listener with JavaCore (using addPreProcessingResourceChangedListener(..., IResourceChangeEvent.PRE_BUILD)). And when notified that the project is closed or re-opened, use JavaCore#setClasspathContainer(...) to notify the infrastructure that the container has changed.

For example:

public class DynamicClasspathInitializer extends ClasspathContainerInitializer implements IResourceChangeListener 
{
	
	{
		JavaCore.addPreProcessingResourceChangedListener(this, IResourceChangeEvent.PRE_BUILD);
	}

    @Override
    public void initialize(IPath containerPath, IJavaProject javaProject) throws CoreException
    {
        IClasspathContainer container = new DynamicClasspathContainer(javaProject);
        JavaCore.setClasspathContainer(containerPath, new IJavaProject[] {javaProject}, new IClasspathContainer[] {container}, null);


    }

	public void resourceChanged(IResourceChangeEvent event) {
		IResourceDelta delta = event.getDelta().findMember(new Path("/ProjectB"));
		if ((delta.getFlags() & IResourceDelta.OPEN) != 0) {
			try {
				initialize(new Path(Activator.CLASSPATH_CONTAINER_ID), JavaCore.create(ResourcesPlugin.getWorkspace().getRoot().getProject("ProjectA")));
			} catch (CoreException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

I'm closing this bug as INVALID. Please reopen if the solution above doesn't work for you.
Comment 2 David Audel CLA 2008-03-25 08:47:08 EDT
Verified for 3.4M6.
Comment 3 James Leone CLA 2008-03-25 12:39:11 EDT
I incorporated the sample code into my plugin and it worked out great!  Thanks again for clarifying my point of problems.  I had a feeling I was missing a step.