Bug 249932 - Clean + project build does not update 'strictly match JRE' problem
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/EECompilationParticipant.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/EECompilationParticipant.java
new file mode 100644
index 0000000..29ad775
--- /dev/null
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/EECompilationParticipant.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.launching;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.compiler.CompilationParticipant;
+import org.eclipse.jdt.launching.IVMInstall;
+import org.eclipse.jdt.launching.JavaRuntime;
+import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
+import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
+
+import com.ibm.icu.text.MessageFormat;
+
+/**
+ * Creates build path errors related to execution environment bindings.
+ * 
+ * @since 3.5
+ */
+public class EECompilationParticipant extends CompilationParticipant {
+	
+	/**
+	 * A set of projects that have been cleaned. When the build finishes for
+	 * a project that has been cleaned, we check for EE problems.
+	 */
+	private Set fCleaned = new HashSet();
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.compiler.CompilationParticipant#isActive(org.eclipse.jdt.core.IJavaProject)
+	 */
+	public boolean isActive(IJavaProject project) {
+		return true;
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.compiler.CompilationParticipant#cleanStarting(org.eclipse.jdt.core.IJavaProject)
+	 */
+	public void cleanStarting(IJavaProject project) {
+		super.cleanStarting(project);
+		fCleaned.add(project);
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.compiler.CompilationParticipant#buildFinished(org.eclipse.jdt.core.IJavaProject)
+	 */
+	public void buildFinished(IJavaProject project) {
+		super.buildFinished(project);
+		if (fCleaned.remove(project)) {
+			String eeId = null;
+			IPath container = null;
+			try {
+				IClasspathEntry[] rawClasspath = project.getRawClasspath();
+				for (int j = 0; j < rawClasspath.length; j++) {
+					IClasspathEntry entry = rawClasspath[j];
+					if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+						IPath path = entry.getPath();
+						if (JavaRuntime.JRE_CONTAINER.equals(path.segment(0))) {
+							container = path;
+							eeId = JREContainerInitializer.getExecutionEnvironmentId(path);
+						}
+					}
+				}
+			} catch (CoreException e) {
+				LaunchingPlugin.log(e);
+			}
+			if (container != null && eeId != null) {
+				IVMInstall vm = JREContainerInitializer.resolveVM(container);
+				validateEnvironment(eeId, project, vm);
+				
+			}
+		}
+	}
+	
+	/**
+	 * Validates the environment, creating a problem marker for the project as required.
+	 * 
+	 * @param id execution environment ID
+	 * @param project associated project
+	 * @param vm VM binding resolved for the project
+	 */
+	private void validateEnvironment(String id, final IJavaProject project, IVMInstall vm) {
+		IExecutionEnvironmentsManager manager = JavaRuntime.getExecutionEnvironmentsManager();
+		final IExecutionEnvironment environment = manager.getEnvironment(id);
+		if (environment != null) {
+			if (vm == null) {
+				String message = MessageFormat.format(
+						LaunchingMessages.LaunchingPlugin_38,
+						new String[]{environment.getId()});
+				createJREContainerProblem(project, message, IMarker.SEVERITY_ERROR);
+			} else if (!environment.isStrictlyCompatible(vm)) {
+				// warn that VM does not match EE
+				// first determine if there is a strictly compatible JRE available
+				IVMInstall[] compatibleVMs = environment.getCompatibleVMs();
+				int exact = 0;
+				for (int i = 0; i < compatibleVMs.length; i++) {
+					if (environment.isStrictlyCompatible(compatibleVMs[i])) {
+						exact++;
+					}
+				}
+				String message = null;
+				if (exact == 0) {
+					message = MessageFormat.format(
+						LaunchingMessages.LaunchingPlugin_35,
+						new String[]{environment.getId()});
+				} else {
+					message = MessageFormat.format(
+							LaunchingMessages.LaunchingPlugin_36,
+							new String[]{environment.getId()});
+				}
+				int sev = getSeverityLevel(JavaRuntime.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE, project.getProject());
+				if (sev != -1) {
+					createJREContainerProblem(project, message, sev);
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Returns the severity for the specific key from the given {@link IProject},
+	 * or -1 if the problem should be ignored.
+	 * If the project does not have project specific settings, the workspace preference
+	 * is returned. If <code>null</code> is passed in as the project the workspace
+	 * preferences are consulted.
+	 * 
+	 * @param prefkey the given preference key
+	 * @param project the given project or <code>null</code>
+	 * @return the severity level for the given preference key or -1
+	 */
+	private int getSeverityLevel(String prefkey, IProject project) {
+		IPreferencesService service = Platform.getPreferencesService();
+		List scopes = new ArrayList();
+		scopes.add(new InstanceScope());
+		if(project != null) {
+			scopes.add(new ProjectScope(project));
+		}
+		String value = service.getString(LaunchingPlugin.ID_PLUGIN, prefkey, null, (IScopeContext[]) scopes.toArray(new IScopeContext[scopes.size()]));
+		if(value == null) {
+			value = LaunchingPlugin.getDefault().getPluginPreferences().getString(prefkey);
+		}
+		if (JavaCore.ERROR.equals(value)) {
+			return IMarker.SEVERITY_ERROR;
+		}
+		if (JavaCore.WARNING.equals(value)) {
+			return IMarker.SEVERITY_WARNING;
+		}
+		return -1;
+	}	
+	
+	/**
+	 * creates a problem marker for a jre container problem
+	 * @param javaProject
+	 * @param message
+	 * @param severity
+	 */
+	private void createJREContainerProblem(IJavaProject javaProject, String message, int severity) {
+		try {
+			IMarker marker = javaProject.getProject().createMarker(LaunchingPlugin.ID_JRE_CONTAINER_MARKER);
+			marker.setAttributes(
+				new String[] {
+						IMarker.MESSAGE,
+						IMarker.SEVERITY,
+						IMarker.LOCATION},
+					new Object[] {
+						message,
+						new Integer(severity),
+						LaunchingMessages.LaunchingPlugin_37
+					});
+		} catch (CoreException e) {
+			return;
+		}
+	}
+}
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingPlugin.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingPlugin.java
index d590dea..745e264 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingPlugin.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingPlugin.java
@@ -33,16 +33,11 @@
 import javax.xml.parsers.FactoryConfigurationError;
 import javax.xml.parsers.ParserConfigurationException;
 
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceChangeEvent;
 import org.eclipse.core.resources.IResourceChangeListener;
-import org.eclipse.core.resources.IResourceDelta;
 import org.eclipse.core.resources.ISaveContext;
 import org.eclipse.core.resources.ISaveParticipant;
 import org.eclipse.core.resources.IWorkspaceRunnable;
-import org.eclipse.core.resources.ProjectScope;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.FileLocator;
@@ -59,9 +54,6 @@
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
 import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.core.runtime.preferences.IPreferencesService;
-import org.eclipse.core.runtime.preferences.IScopeContext;
-import org.eclipse.core.runtime.preferences.InstanceScope;
 import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.IDebugEventSetListener;
@@ -80,8 +72,6 @@
 import org.eclipse.jdt.launching.IVMInstallChangedListener;
 import org.eclipse.jdt.launching.JavaRuntime;
 import org.eclipse.jdt.launching.VMStandin;
-import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
-import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
 import org.eclipse.jdt.launching.sourcelookup.ArchiveSourceLocation;
 import org.osgi.framework.BundleContext;
 import org.w3c.dom.Document;
@@ -506,7 +496,7 @@
 		getPluginPreferences().addPropertyChangeListener(this);
 
 		JavaRuntime.addVMInstallChangedListener(this);
-		ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_BUILD);
+		ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_CLOSE);
 		DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
 		DebugPlugin.getDefault().addDebugEventListener(this);
 	}
@@ -755,42 +745,12 @@
 	}
 
 	/**
-	 * Clear the archive cache when a project is about to be deleted.
-	 * Warn when a build path changes and references an execution environment
-	 * that does not have a perfect match.
+	 * Clear the archive cache when a project is about to be deleted/closed.
 	 * 
 	 * @see IResourceChangeListener#resourceChanged(IResourceChangeEvent)
 	 */
 	public void resourceChanged(IResourceChangeEvent event) {
 		ArchiveSourceLocation.closeArchives();
-		if (event.getType() == IResourceChangeEvent.PRE_BUILD) {
-			IResourceDelta delta = event.getDelta();
-			IResourceDelta[] projectDeltas = delta.getAffectedChildren();
-			for (int i = 0, length = projectDeltas.length; i < length; i++) {
-				IResourceDelta projectDelta = projectDeltas[i];
-				IResourceDelta classpathDelta = projectDelta.findMember(new Path(".classpath")); //$NON-NLS-1$
-				if (classpathDelta != null || (projectDelta.getFlags() & IResourceDelta.DESCRIPTION) > 0) {
-					IJavaProject project = (IJavaProject) JavaCore.create(projectDelta.getResource());
-					if (project != null && project.exists()) {
-						try {
-							IClasspathEntry[] rawClasspath = project.getRawClasspath();
-							for (int j = 0; j < rawClasspath.length; j++) {
-								IClasspathEntry entry = rawClasspath[j];
-								if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
-									IPath path = entry.getPath();
-									if (JavaRuntime.JRE_CONTAINER.equals(path.segment(0))) {
-										IVMInstall vm = JREContainerInitializer.resolveVM(path);
-										validateEnvironment(path, project, vm);
-									}
-								}
-							}
-						} catch (CoreException e) {
-							LaunchingPlugin.log(e);
-						}
-					}
-				}
-			}
-		}
 	}
 
 	/**
@@ -1067,112 +1027,6 @@
 		IStatus status = new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), 0, message, exception);
 		throw new CoreException(status);
 	}
-	
-	/**
-	 * Validates the environment
-	 * @param containerPath
-	 * @param project
-	 * @param vm
-	 */
-	private void validateEnvironment(IPath containerPath, final IJavaProject project, IVMInstall vm) {
-		try {
-			project.getProject().deleteMarkers(ID_JRE_CONTAINER_MARKER, false, IResource.DEPTH_ZERO);
-		} catch (CoreException e) {
-			LaunchingPlugin.log(e);
-		}
-		String id = JREContainerInitializer.getExecutionEnvironmentId(containerPath);
-		if (id != null) {
-			IExecutionEnvironmentsManager manager = JavaRuntime.getExecutionEnvironmentsManager();
-			final IExecutionEnvironment environment = manager.getEnvironment(id);
-			if (environment != null) {
-				if (vm == null) {
-					String message = MessageFormat.format(
-							LaunchingMessages.LaunchingPlugin_38,
-							new String[]{environment.getId()});
-					createJREContainerProblem(project, message, IMarker.SEVERITY_ERROR);
-				} else if (!environment.isStrictlyCompatible(vm)) {
-					// warn that VM does not match EE
-					// first determine if there is a strictly compatible JRE available
-					IVMInstall[] compatibleVMs = environment.getCompatibleVMs();
-					int exact = 0;
-					for (int i = 0; i < compatibleVMs.length; i++) {
-						if (environment.isStrictlyCompatible(compatibleVMs[i])) {
-							exact++;
-						}
-					}
-					String message = null;
-					if (exact == 0) {
-						message = MessageFormat.format(
-							LaunchingMessages.LaunchingPlugin_35,
-							new String[]{environment.getId()});
-					} else {
-						message = MessageFormat.format(
-								LaunchingMessages.LaunchingPlugin_36,
-								new String[]{environment.getId()});
-					}
-					int sev = getSeverityLevel(JavaRuntime.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE, project.getProject());
-					if (sev != -1) {
-						createJREContainerProblem(project, message, sev);
-					}
-				}
-			}
-		}
-	}
-	
-	/**
-	 * Returns the severity for the specific key from the given {@link IProject},
-	 * or -1 if the problem should be ignored.
-	 * If the project does not have project specific settings, the workspace preference
-	 * is returned. If <code>null</code> is passed in as the project the workspace
-	 * preferences are consulted.
-	 * 
-	 * @param prefkey the given preference key
-	 * @param project the given project or <code>null</code>
-	 * @return the severity level for the given preference key or -1
-	 */
-	private int getSeverityLevel(String prefkey, IProject project) {
-		IPreferencesService service = Platform.getPreferencesService();
-		List scopes = new ArrayList();
-		scopes.add(new InstanceScope());
-		if(project != null) {
-			scopes.add(new ProjectScope(project));
-		}
-		String value = service.getString(LaunchingPlugin.ID_PLUGIN, prefkey, null, (IScopeContext[]) scopes.toArray(new IScopeContext[scopes.size()]));
-		if(value == null) {
-			value = getPluginPreferences().getString(prefkey);
-		}
-		if (JavaCore.ERROR.equals(value)) {
-			return IMarker.SEVERITY_ERROR;
-		}
-		if (JavaCore.WARNING.equals(value)) {
-			return IMarker.SEVERITY_WARNING;
-		}
-		return -1;
-	}	
-	
-	/**
-	 * creates a problem marker for a jre container problem
-	 * @param javaProject
-	 * @param message
-	 * @param severity
-	 */
-	private void createJREContainerProblem(IJavaProject javaProject, String message, int severity) {
-		try {
-			IMarker marker = javaProject.getProject().createMarker(ID_JRE_CONTAINER_MARKER);
-			marker.setAttributes(
-				new String[] {
-						IMarker.MESSAGE,
-						IMarker.SEVERITY,
-						IMarker.LOCATION},
-					new Object[] {
-						message,
-						new Integer(severity),
-						LaunchingMessages.LaunchingPlugin_37
-					});
-		} catch (CoreException e) {
-			return;
-		}
-	}
 }
 
  
diff --git a/org.eclipse.jdt.launching/plugin.xml b/org.eclipse.jdt.launching/plugin.xml
index 883bcfa..a285772 100644
--- a/org.eclipse.jdt.launching/plugin.xml
+++ b/org.eclipse.jdt.launching/plugin.xml
@@ -264,5 +264,16 @@
             id="org.eclipse.jdt.launching.defaultParticipant">
       </ruleParticipant>
    </extension>
+      <extension
+            point="org.eclipse.jdt.core.compilationParticipant">
+         <compilationParticipant
+               class="org.eclipse.jdt.internal.launching.EECompilationParticipant"
+               createsProblems="true"
+               id="org.eclipse.jdt.launching.compilationParticipant.ee">
+            <managedMarker
+                  markerType="org.eclipse.jdt.launching.jreContainerMarker">
+            </managedMarker>
+         </compilationParticipant>
+      </extension>
      
 </plugin>