/******************************************************************************* * Copyright (c) 2008, 2015 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.ltk.core.refactoring.tests.resource; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.operations.IOperationHistory; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.commands.operations.OperationHistoryFactory; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.ltk.core.refactoring.CheckConditionsOperation; import org.eclipse.ltk.core.refactoring.PerformRefactoringOperation; import org.eclipse.ltk.core.refactoring.Refactoring; import org.eclipse.ltk.core.refactoring.RefactoringContribution; import org.eclipse.ltk.core.refactoring.RefactoringCore; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.resource.DeleteResourcesDescriptor; import org.eclipse.ltk.core.refactoring.resource.RenameResourceDescriptor; import org.eclipse.ltk.core.refactoring.tests.FileSystemHelper; import org.eclipse.ltk.core.refactoring.tests.RefactoringCoreTestPlugin; import org.eclipse.ltk.core.refactoring.tests.participants.ElementRenameProcessor; import org.eclipse.ltk.core.refactoring.tests.participants.ElementRenameRefactoring; import org.eclipse.ltk.core.refactoring.tests.util.SimpleTestProject; import org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; public class ResourceRefactoringUndoTests extends TestCase { private static final String TEST_NEWPROJECT_NAME= "projectTestNew"; private static final String TEST_FOLDER_NAME= "test"; private static final String TEST_NEWFOLDER_NAME= "testNew"; private static final String TEST_FILE_NAME= "myFile.txt"; private static final String TEST_NEWFILE_NAME= "newFile.txt"; private static final String TEST_LINKEDFOLDER_NAME= "linkedFolder"; private static final String TEST_LINKEDFILE_NAME= "linkedFile.txt"; private static final String TEST_SUBFOLDER_NAME= "subFolder"; private static List<String> fileNameExcludes= new ArrayList<>(); static { fileNameExcludes.add(".project"); } public static Test suite() { TestSuite suite= new TestSuite(ResourceRefactoringUndoTests.class.getName()); suite.addTestSuite(ResourceRefactoringUndoTests.class); return suite; } private static final String CONTENT= "hello"; private SimpleTestProject fProject; private IFolder testFolder; private IFile testFile; private IOperationHistory history; private IUndoContext context; private final Set<IFileStore> storesToDelete= new HashSet<>(); private IFolder testLinkedFolder; private IFile testLinkedFile; private IFolder testSubFolder; @Override protected void setUp() throws Exception { fProject= new SimpleTestProject(); testFolder= fProject.createFolder(TEST_FOLDER_NAME); testFile= fProject.createFile(testFolder, TEST_FILE_NAME, CONTENT); // Create links by first creating the backing content... IFileStore folderStore= getTempStore(); IFileStore fileStore= getTempStore(); IPath folderLocation= URIUtil.toPath(folderStore.toURI()); IPath fileLocation= URIUtil.toPath(fileStore.toURI()); folderStore.mkdir(EFS.NONE, getMonitor()); fileStore.openOutputStream(EFS.NONE, getMonitor()).close(); // Then create the workspace objects testLinkedFolder= testFolder.getFolder(TEST_LINKEDFOLDER_NAME); testLinkedFolder.createLink(folderLocation, IResource.NONE, getMonitor()); assertTrue(testLinkedFolder.exists()); testLinkedFile= testFolder.getFile(TEST_LINKEDFILE_NAME); testLinkedFile.createLink(fileLocation, IResource.NONE, getMonitor()); // subfolder testSubFolder= testFolder.getFolder(TEST_SUBFOLDER_NAME); testSubFolder.create(true, true, getMonitor()); history= OperationHistoryFactory.getOperationHistory(); context= RefactoringCorePlugin.getUndoContext(); } @Override protected void tearDown() throws Exception { fProject.delete(); final IFileStore[] toDelete= storesToDelete.toArray(new IFileStore[storesToDelete.size()]); storesToDelete.clear(); for (int i= 0; i < toDelete.length; i++) { clear(toDelete[i]); } } public void testFileRenameUndoRedoLTK() throws ExecutionException, CoreException { RefactoringContribution renameContribution= RefactoringCore.getRefactoringContribution(RenameResourceDescriptor.ID); RenameResourceDescriptor desc= (RenameResourceDescriptor) renameContribution.createDescriptor(); desc.setResourcePath(testFile.getFullPath()); desc.setNewName(TEST_NEWFILE_NAME); PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); FileSnapshot snap= new FileSnapshot(testFile); execute(op); IFile renamedFile= testFolder.getFile(TEST_NEWFILE_NAME); assertTrue("File rename failed", renamedFile.exists()); snap.name= TEST_NEWFILE_NAME; assertTrue("File CONTENT was altered on rename", snap.isValid(testFolder)); undo(); snap.name= TEST_FILE_NAME; assertTrue("File CONTENT was altered on undo rename", snap.isValid(testFolder)); assertFalse("Undo rename failed", renamedFile.exists()); redo(); snap.name= TEST_NEWFILE_NAME; assertTrue("File CONTENT was altered on redo rename", snap.isValid(testFolder)); } public void testFolderRenameUndoRedoLTK() throws ExecutionException, CoreException { RefactoringContribution renameContribution= RefactoringCore.getRefactoringContribution(RenameResourceDescriptor.ID); RenameResourceDescriptor desc= (RenameResourceDescriptor) renameContribution.createDescriptor(); desc.setResourcePath(testFolder.getFullPath()); desc.setNewName(TEST_NEWFOLDER_NAME); PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); FolderSnapshot snap= new FolderSnapshot(testFolder); execute(op); IFolder renamedFolder= fProject.getProject().getFolder(TEST_NEWFOLDER_NAME); assertTrue("Project rename failed", renamedFolder.exists()); snap.name= TEST_NEWFOLDER_NAME; assertTrue("Folder CONTENT was altered on rename", snap.isValid(fProject.getProject())); undo(); snap.name= TEST_FOLDER_NAME; assertTrue("Folder CONTENT was altered on undo rename", snap.isValid(fProject.getProject())); assertFalse("Undo rename failed", renamedFolder.exists()); redo(); snap.name= TEST_NEWFOLDER_NAME; assertTrue("Folder CONTENT was altered on redo rename", snap.isValid(fProject.getProject())); } public void testProjectRenameUndoRedoLTK() throws ExecutionException, CoreException { IProject renamedProject= null; try { RefactoringContribution renameContribution= RefactoringCore.getRefactoringContribution(RenameResourceDescriptor.ID); RenameResourceDescriptor desc= (RenameResourceDescriptor) renameContribution.createDescriptor(); desc.setResourcePath(fProject.getProject().getFullPath()); desc.setNewName(TEST_NEWPROJECT_NAME); PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); ProjectSnapshot snap= new ProjectSnapshot(fProject.getProject()); execute(op); renamedProject= getWorkspaceRoot().getProject(TEST_NEWPROJECT_NAME); assertTrue("Project rename failed", renamedProject.exists()); snap.name= TEST_NEWPROJECT_NAME; assertTrue("Project CONTENT was altered on rename", snap.isValid()); undo(); snap.name= SimpleTestProject.TEST_PROJECT_NAME; assertTrue("Project CONTENT was altered on undo rename", snap.isValid()); assertFalse("Undo rename failed", renamedProject.exists()); redo(); snap.name= TEST_NEWPROJECT_NAME; assertTrue("Project CONTENT was altered on redo rename", snap.isValid()); } finally { renamedProject.delete(true, true, null); } } public void testFileDeleteUndoRedoLTK() throws ExecutionException, CoreException { RefactoringContribution renameContribution= RefactoringCore.getRefactoringContribution(DeleteResourcesDescriptor.ID); DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor(); desc.setResourcePaths(new IPath[] { testFile.getFullPath() }); PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); FileSnapshot snap= new FileSnapshot(testFile); execute(op); assertFalse("File delete failed", testFile.exists()); undo(); assertTrue("File recreation failed", testFile.exists()); assertTrue("File CONTENT was altered on undo", snap.isValid(testFile.getParent())); redo(); assertFalse("Redo delete failed", testFile.exists()); } public void testFileLinkedDeleteUndoRedoLTK() throws ExecutionException, CoreException { RefactoringContribution renameContribution= RefactoringCore.getRefactoringContribution(DeleteResourcesDescriptor.ID); DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor(); desc.setResourcePaths(new IPath[] { testLinkedFile.getFullPath() }); PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); FileSnapshot snap= new FileSnapshot(testLinkedFile); execute(op); assertFalse("File delete failed", testLinkedFile.exists()); undo(); assertTrue("File recreation failed", testLinkedFile.exists()); assertTrue("File CONTENT was altered on undo", snap.isValid(testLinkedFile.getParent())); redo(); assertFalse("Redo delete failed", testLinkedFile.exists()); } public void testFolderDeleteUndoRedoLTK() throws ExecutionException, CoreException { RefactoringContribution renameContribution= RefactoringCore.getRefactoringContribution(DeleteResourcesDescriptor.ID); DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor(); desc.setResourcePaths(new IPath[] { testSubFolder.getFullPath() }); PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); FolderSnapshot snap= new FolderSnapshot(testSubFolder); execute(op); assertFalse("Folder delete failed", testSubFolder.exists()); undo(); assertTrue("Folder recreation failed", testSubFolder.exists()); assertTrue("Folder CONTENT was altered on undo", snap.isValid(testSubFolder.getParent())); redo(); assertFalse("Redo delete failed", testSubFolder.exists()); } public void testFolderDeleteLinkedUndoRedoLTK() throws ExecutionException, CoreException { RefactoringContribution renameContribution= RefactoringCore.getRefactoringContribution(DeleteResourcesDescriptor.ID); DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor(); desc.setResourcePaths(new IPath[] { testLinkedFolder.getFullPath() }); PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); FolderSnapshot snap= new FolderSnapshot(testLinkedFolder); execute(op); assertFalse("Folder delete failed", testLinkedFolder.exists()); undo(); assertTrue("Folder recreation failed", testLinkedFolder.exists()); assertTrue("Folder CONTENT was altered on undo", snap.isValid(testLinkedFolder.getParent())); redo(); assertFalse("Redo delete failed", testLinkedFolder.exists()); } public void testFolderDeleteLinkedDeletedOnFilesystemUndoRedoLTK() throws ExecutionException, CoreException { RefactoringContribution deleteContribution= RefactoringCore.getRefactoringContribution(DeleteResourcesDescriptor.ID); DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) deleteContribution.createDescriptor(); desc.setResourcePaths(new IPath[] { testLinkedFolder.getFullPath() }); PerformRefactoringOperation op= new PerformRefactoringOperation( desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); FolderSnapshot snap= new FolderSnapshot(testLinkedFolder); // Create a subfolder containing a file under the linked folder. IFolder subfolder= testLinkedFolder.getFolder("A"); subfolder.create(true, true, getMonitor()); IFile file= subfolder.getFile("test.txt"); file.create(new ByteArrayInputStream("test contents".getBytes(StandardCharsets.UTF_8)), true, getMonitor()); // Delete the target of the linked folder on the file system making the linked folder out of sync // with the file system. IFileStore folderStore= EFS.getStore(testLinkedFolder.getLocationURI()); folderStore.delete(EFS.NONE, getMonitor()); // Delete the target folder on the file system. execute(op); assertFalse("Folder delete failed", testLinkedFolder.exists()); undo(); assertTrue("Folder recreation failed", testLinkedFolder.exists()); assertTrue("Folder CONTENT was altered on undo", snap.isValid(testLinkedFolder.getParent())); redo(); assertFalse("Redo delete failed", testLinkedFolder.exists()); } public void testProjectDeleteUndoRedoLTK() throws ExecutionException, CoreException { RefactoringContribution renameContribution= RefactoringCore.getRefactoringContribution(DeleteResourcesDescriptor.ID); DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor(); desc.setResourcePaths(new IPath[] { fProject.getProject().getFullPath() }); PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); execute(op); assertFalse("Project delete failed", fProject.getProject().exists()); undo(); assertTrue("Project recreation failed", fProject.getProject().exists()); // Ideally we could run this test everytime, but it fails intermittently // because opening the recreated project occurs in the background, and // the creation of the workspace representation for the disk contents // may not have happened yet. This test always passes under debug where // timing can be controlled. // *********** // assertTrue("Project CONTENT was altered on undo", snap.isValid()); // ************ redo(); assertFalse("Redo delete failed", fProject.getProject().exists()); // We undo again so that the project will exist during teardown and // get cleaned up. Otherwise some CONTENT is left on disk. undo(); } public void testProjectClosedDeleteUndoRedoLTK() throws ExecutionException, CoreException { fProject.getProject().close(getMonitor()); testProjectDeleteUndoRedoLTK(); } public void testProjectDeleteWithContentUndoRedoLTK() throws ExecutionException, CoreException { RefactoringContribution renameContribution= RefactoringCore.getRefactoringContribution(DeleteResourcesDescriptor.ID); DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor(); desc.setResourcePaths(new IPath[] { fProject.getProject().getFullPath() }); desc.setDeleteContents(true); PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS); // we don't snapshot since CONTENT will be deleted execute(op); assertFalse("Project delete failed", fProject.getProject().exists()); undo(); assertTrue("Project was recreated", fProject.getProject().exists()); redo(); assertFalse("Redo delete failed", fProject.getProject().exists()); } public void testProjectClosedDeleteWithContentUndoRedoLTK() throws ExecutionException, CoreException { fProject.getProject().close(getMonitor()); testProjectDeleteWithContentUndoRedoLTK(); } public void testPreChangeUndoRedoLTK() throws ExecutionException, CoreException { Refactoring ref= new ElementRenameRefactoring(ElementRenameRefactoring.WORKING | ElementRenameRefactoring.ALWAYS_ENABLED | ElementRenameRefactoring.PRE_CHANGE); PerformRefactoringOperation op= new PerformRefactoringOperation(ref, CheckConditionsOperation.ALL_CONDITIONS); execute(op); List<String> h= ElementRenameProcessor.fHistory; // Strictly speaking, the execution of these things does not need to be in exactly this // order, but it's an easy way to check. Of course there are some dependencies on the // order (participant-pre-exec, main-exec, participant-exec) int i= 0; assertEquals(ElementRenameProcessor.MAIN_CREATE, h.get(i++)); assertEquals(ElementRenameProcessor.WORKING_CREATE, h.get(i++)); assertEquals(ElementRenameProcessor.WORKINGPRE_CREATEPRE, h.get(i++)); assertEquals(ElementRenameProcessor.WORKINGPRE_CREATE, h.get(i++)); assertEquals(ElementRenameProcessor.WORKINGPRE_EXECPRE, h.get(i++)); assertEquals(ElementRenameProcessor.MAIN_EXEC, h.get(i++)); assertEquals(ElementRenameProcessor.WORKING_EXEC, h.get(i++)); assertEquals(ElementRenameProcessor.WORKINGPRE_EXEC, h.get(i++)); undo(); assertEquals(ElementRenameProcessor.WORKINGPRE_EXEC_UNDO, h.get(i++)); assertEquals(ElementRenameProcessor.WORKING_EXEC_UNDO, h.get(i++)); assertEquals(ElementRenameProcessor.MAIN_EXEC_UNDO, h.get(i++)); assertEquals(ElementRenameProcessor.WORKINGPRE_EXECPRE_UNDO, h.get(i++)); redo(); assertEquals(ElementRenameProcessor.WORKINGPRE_EXECPRE, h.get(i++)); assertEquals(ElementRenameProcessor.MAIN_EXEC, h.get(i++)); assertEquals(ElementRenameProcessor.WORKING_EXEC, h.get(i++)); assertEquals(ElementRenameProcessor.WORKINGPRE_EXEC, h.get(i++)); } private void execute(PerformRefactoringOperation op) throws CoreException { ResourcesPlugin.getWorkspace().run(op, getMonitor()); } private IWorkspaceRoot getWorkspaceRoot() { return ResourcesPlugin.getWorkspace().getRoot(); } private void undo() throws ExecutionException { assertTrue("Operation can be undone", history.canUndo(context)); IStatus status= history.undo(context, getMonitor(), null); assertTrue("Undo should be OK status", status.isOK()); } private void redo() throws ExecutionException { assertTrue("Operation can be redone", history.canRedo(context)); IStatus status= history.redo(context, getMonitor(), null); assertTrue("Redo should be OK status", status.isOK()); } private IProgressMonitor getMonitor() { return null; } private ResourceSnapshot snapshotFromResource(IResource resource) throws CoreException { if (resource instanceof IFile) return new FileSnapshot((IFile) resource); if (resource instanceof IFolder) return new FolderSnapshot((IFolder) resource); if (resource instanceof IProject) return new ProjectSnapshot((IProject) resource); fail("Unknown resource type"); // making compiler happy return new FileSnapshot((IFile) resource); } /* * reads testFile CONTENT and returns string */ private String readContent(IFile file) throws CoreException { InputStream is= file.getContents(); String encoding= file.getCharset(); if (is == null) return null; try (BufferedReader reader= new BufferedReader(new InputStreamReader(is, encoding))) { StringBuffer buffer= new StringBuffer(); char[] part= new char[2048]; int read= 0; while ((read= reader.read(part)) != -1) buffer.append(part, 0, read); return buffer.toString(); } catch (IOException ex) { throw new CoreException(new Status(IStatus.ERROR, RefactoringCoreTestPlugin.getPluginId(), ex.getMessage())); } } /** * Returns a FileStore instance backed by storage in a temporary location. The returned store * will not exist, but will belong to an existing parent. The tearDown method in this class will * ensure the location is deleted after the test is completed. * * @return The temp filestore to use */ private IFileStore getTempStore() { IFileStore store= EFS.getLocalFileSystem().getStore(FileSystemHelper.getRandomLocation(FileSystemHelper.getTempDir())); storesToDelete.add(store); return store; } private void clear(IFileStore store) { try { store.delete(EFS.NONE, null); } catch (CoreException e) { } } class FileSnapshot extends ResourceSnapshot { String content; URI location; MarkerSnapshot[] markerSnapshots; FileSnapshot(IFile file) throws CoreException { content= readContent(file); name= file.getName(); if (file.isLinked()) { location= file.getLocationURI(); } IMarker[] markers= file.findMarkers(null, true, IResource.DEPTH_INFINITE); markerSnapshots= new MarkerSnapshot[markers.length]; for (int i= 0; i < markers.length; i++) { markerSnapshots[i]= new MarkerSnapshot(markers[i]); } } @Override boolean isValid(IResource parent) throws CoreException { IResource resource= getWorkspaceRoot().findMember(parent.getFullPath().append(name)); if (resource == null || !(resource instanceof IFile)) { return false; } IFile file= (IFile) resource; boolean contentMatch= readContent(file).equals(content); if (file.isLinked()) { contentMatch= contentMatch && file.getLocationURI().equals(location); } if (!contentMatch) { return false; } for (int i= 0; i < markerSnapshots.length; i++) { if (!markerSnapshots[i].existsOn(resource)) { return false; } } return true; } } class FolderSnapshot extends ResourceSnapshot { URI location; ResourceSnapshot[] memberSnapshots; FolderSnapshot(IFolder folder) throws CoreException { name= folder.getName(); if (folder.isLinked()) { location= folder.getLocationURI(); } IResource[] members= folder.members(); memberSnapshots= new ResourceSnapshot[members.length]; for (int i= 0; i < members.length; i++) { memberSnapshots[i]= snapshotFromResource(members[i]); } } @Override boolean isValid(IResource parent) throws CoreException { IResource resource= getWorkspaceRoot().findMember(parent.getFullPath().append(name)); if (resource == null || !(resource instanceof IFolder)) { return false; } IFolder folder= (IFolder) resource; if (folder.isLinked()) { if (!folder.getLocationURI().equals(location)) { return false; } } for (int i= 0; i < memberSnapshots.length; i++) { if (!fileNameExcludes.contains(memberSnapshots[i].name)) { if (!memberSnapshots[i].isValid(folder)) { return false; } } } return true; } } class MarkerSnapshot { String type; Map<String, Object> attributes; MarkerSnapshot(IMarker marker) throws CoreException { type= marker.getType(); attributes= marker.getAttributes(); } boolean existsOn(IResource resource) throws CoreException { // comparison is based on equality of attributes, since id will // change on create/delete/recreate sequence IMarker[] markers= resource.findMarkers(type, false, IResource.DEPTH_ZERO); for (int i= 0; i < markers.length; i++) { if (markers[i].getAttributes().equals(attributes)) { return true; } } return false; } } class ProjectSnapshot extends ResourceSnapshot { ResourceSnapshot[] memberSnapshots; ProjectSnapshot(IProject project) throws CoreException { name= project.getName(); boolean open= project.isOpen(); if (!open) { project.open(null); } IResource[] members= project.members(); memberSnapshots= new ResourceSnapshot[members.length]; for (int i= 0; i < members.length; i++) { memberSnapshots[i]= snapshotFromResource(members[i]); } if (!open) { project.close(null); } } @Override boolean isValid(IResource parent) throws CoreException { IResource resource= getWorkspaceRoot().findMember(parent.getFullPath().append(name)); if (resource == null || !(resource instanceof IProject)) { return false; } IProject project= (IProject) resource; // Must open it to validate the CONTENT boolean open= project.isOpen(); if (!open) { project.open(null); } for (int i= 0; i < memberSnapshots.length; i++) { if (!fileNameExcludes.contains(memberSnapshots[i].name)) { if (!memberSnapshots[i].isValid(resource)) { return false; } } } if (!open) { project.close(null); } return true; } boolean isValid() throws CoreException { return isValid(getWorkspaceRoot()); } } abstract class ResourceSnapshot { String name; abstract boolean isValid(IResource parent) throws CoreException; IWorkspaceRoot getWorkspaceRoot() { return ResourcesPlugin.getWorkspace().getRoot(); } } }