/******************************************************************************* * Copyright © 2000, 2013 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.edt.ide.core.internal.builder; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; 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.IResourceProxy; import org.eclipse.core.resources.IResourceProxyVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.edt.compiler.internal.core.builder.BuildException; import org.eclipse.edt.ide.core.internal.dependency.DependencyGraph; import org.eclipse.edt.ide.core.internal.dependency.DependencyGraphManager; import org.eclipse.edt.ide.core.internal.dependency.IFunctionRequestor; import org.eclipse.edt.ide.core.internal.generation.GenerationBuildManager; import org.eclipse.edt.ide.core.internal.lookup.FileInfoManager; import org.eclipse.edt.ide.core.internal.lookup.IFileInfo; import org.eclipse.edt.ide.core.internal.lookup.ProjectBuildPathEntryManager; import org.eclipse.edt.ide.core.internal.lookup.ProjectBuildPathManager; import org.eclipse.edt.ide.core.internal.lookup.ProjectEnvironmentManager; import org.eclipse.edt.ide.core.internal.lookup.ProjectInfoManager; import org.eclipse.edt.ide.core.internal.lookup.ZipFileBuildPathEntryManager; import org.eclipse.edt.ide.core.internal.model.EGLProject; import org.eclipse.edt.mof.utils.NameUtile; /** * @author cduval * */ public class ResourceChangeProcessor implements IResourceChangeListener { public class ContextSpecificMarkerRemovalRequest { private String functionProjectName; private String functionPackageName; private String functionPartName; private IPath contextFilePath; private String contextPartName; public ContextSpecificMarkerRemovalRequest(String functionProjectName, String functionPackageName, String functionPartName, String contextPartName, IPath contextFilePath){ this.functionProjectName = functionProjectName; this.functionPackageName = functionPackageName; this.functionPartName = functionPartName; this.contextPartName = contextPartName; this.contextFilePath = contextFilePath; } } private Map contextSpecificMarkersForDeletion = new HashMap(); private Set removedProjects = new HashSet(); public void resourceChanged(IResourceChangeEvent event) { final boolean projectDeleting = event.getType() == IResourceChangeEvent.PRE_DELETE; final boolean projectClosing = event.getType() == IResourceChangeEvent.PRE_CLOSE; final boolean preBuilding = event.getType() == IResourceChangeEvent.PRE_BUILD; final boolean postChange = event.getType() == IResourceChangeEvent.POST_CHANGE; if (projectDeleting || projectClosing) { this.processProjectDelete((IProject)event.getResource()); } else if (preBuilding) { this.removeContextSpecificMarkers(); } else if (postChange) { IResourceDelta delta = event.getDelta(); IResourceDelta[] affectedChildren = delta.getAffectedChildren(); for (IResourceDelta child : affectedChildren) { if ((child.getFlags() & IResourceDelta.OPEN) != 0) { IResource resource = child.getResource(); // No need to check if the project is open, if it was being closed we wouldn't have gotten here. if (resource.getType() == IResource.PROJECT && EGLProject.hasEGLNature((IProject)resource)) { ProjectSettingsListenerManager.getInstance().addProject((IProject)resource); } } else if (child.getKind() == IResourceDelta.CHANGED) { IResource resource = child.getResource(); if (resource.getType() == IResource.PROJECT && EGLProject.hasEGLNature((IProject)resource)) { // We only care if the .project file changed, since it might mean we added the EGL nature to the project, // however it's faster to check if the map in ProjectSettingsListenerManager already has an entry for the project, // than to process its grandkids to see if .project was changed. ProjectSettingsListenerManager.getInstance().addProject((IProject)resource); } } } } } public void processProjectClose(IProject project){ // We have to treat a project close like a project delete because of top level functions. // When a project is closed/deleted, all context specific error markers are removed from referenced // projects. If we did not treat a close as a delete, when this project was reopened, we would not // rebuild this project to produce the context specific markers in the required projects. processProjectDelete(project); } public void processProjectDelete(IProject project){ if (EGLProject.hasEGLNature(project)) { removedProjects.add(project.getName()); collectContextSpecificMarkersForRemoval(project); ZipFileBuildPathEntryManager.getInstance().clear(project); FileInfoManager.getInstance().removeProject(project); // Cached FileInfos ProjectEnvironmentManager.getInstance().remove(project); // Environment ProjectBuildPathEntryManager.getInstance().remove(project); ProjectBuildPathManager.getInstance().remove(project); ProjectInfoManager.getInstance().remove(project); // ProjectInfo DependencyGraphManager.getInstance().remove(project); // Dependency Graph BuildManager.getInstance().removeProject(project); // Build Manager GenerationBuildManager.getInstance().removeProject(project); // Generation Build Manager DuplicatePartManager.getInstance().remove(project); // Duplicate Parts ProjectSettingsListenerManager.getInstance().removeProject(project); } } // Visit every part in this project and create a request to remove all markers on functions in other projects that were created within the context of a part in this project private void collectContextSpecificMarkersForRemoval(final IProject project) { try{ IContainer[] sourceLocations = ProjectBuildPathManager.getInstance().getProjectBuildPath(project).getSourceLocations(); for (int i = 0, l = sourceLocations.length; i < l; i++) { final IContainer sourceLocation = sourceLocations[i]; final int segmentCount = sourceLocation.getFullPath().segmentCount(); IResource[] children = sourceLocation.members(); for (int j = 0; j < children.length; j++) { children[j].accept( new IResourceProxyVisitor() { public boolean visit(IResourceProxy proxy) throws CoreException { IResource resource = proxy.requestResource(); switch(proxy.getType()) { case IResource.FILE : final IFile file = (IFile)resource; if (org.eclipse.edt.ide.core.internal.model.Util.isEGLFileName(resource.getName())) { String packageName = NameUtile.getAsName(org.eclipse.edt.ide.core.internal.utils.Util.pathToQualifiedName(resource.getFullPath().removeFirstSegments(segmentCount).removeLastSegments(1))); IFileInfo fileInfo = FileInfoManager.getInstance().getFileInfo(project, file.getProjectRelativePath()); // a File Info is null if this project hasn't been built yet if(fileInfo != null){ Set partNames = fileInfo.getPartNames(); for (Iterator iter = partNames.iterator(); iter.hasNext();) { final String partName = (String) iter.next(); DependencyGraph dependencyGraph = DependencyGraphManager.getInstance().getDependencyGraph(project); dependencyGraph.findFunctionDependencies(packageName, partName, new IFunctionRequestor(){ @Override public void acceptFunction(String functionProjectName, String functionPackageName, String functionPartName) { List changes = (List)contextSpecificMarkersForDeletion.get(functionProjectName); if(changes == null){ changes = new ArrayList(); contextSpecificMarkersForDeletion.put(functionProjectName, changes); } changes.add(new ContextSpecificMarkerRemovalRequest(functionProjectName, functionPackageName, functionPartName, partName, file.getFullPath())); } }); } } } return false; } return true; } }, IResource.NONE ); } } }catch(CoreException e){ throw new BuildException(e); } } private void removeContextSpecificMarkers(){ if(contextSpecificMarkersForDeletion.size() > 0){ try{ for (Iterator iter = contextSpecificMarkersForDeletion.keySet().iterator(); iter.hasNext();) { String projectName = (String)iter.next(); // Don't attempt to remove the markers from a project that is now deleted if(!removedProjects.contains(projectName)){ List changes = (List)contextSpecificMarkersForDeletion.get(projectName); for (Iterator iterator = changes.iterator(); iterator.hasNext();) { ContextSpecificMarkerRemovalRequest removalRequest = (ContextSpecificMarkerRemovalRequest) iterator.next(); Util.removeMarkersFromInvokedFunctions(removalRequest.contextPartName, removalRequest.contextFilePath, removalRequest.functionProjectName, removalRequest.functionPackageName, removalRequest.functionPartName); } } } }finally{ contextSpecificMarkersForDeletion.clear(); } } removedProjects.clear(); } }