# This patch file was generated by NetBeans IDE # This patch can be applied using context Tools: Apply Diff Patch action on respective folder. # It uses platform neutral UTF-8 encoding. # Above lines and this line are ignored by the patching process. Index: projects/projectapi/src/org/netbeans/api/project/ProjectManager.java --- projects/projectapi/src/org/netbeans/api/project/ProjectManager.java Base (1.38) +++ projects/projectapi/src/org/netbeans/api/project/ProjectManager.java Locally Modified (Based On 1.38) @@ -41,6 +41,7 @@ package org.netbeans.api.project; +import java.io.File; import java.io.IOException; import java.lang.ref.Reference; import java.util.Arrays; @@ -50,6 +51,7 @@ import java.util.Map; import java.util.Set; import java.util.WeakHashMap; +import java.util.concurrent.Executor; import java.util.logging.Level; import java.util.logging.Logger; import org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation; @@ -61,7 +63,10 @@ import org.openide.filesystems.FileChangeListener; import org.openide.filesystems.FileEvent; import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileStateInvalidException; +import org.openide.filesystems.FileSystem; import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.LookupEvent; import org.openide.util.LookupListener; @@ -107,7 +112,37 @@ return DEFAULT; } - private static final Mutex MUTEX = new Mutex(); + private static final Executor FS_EXEC = new Executor() { + public void execute(final Runnable command) { + FileSystem fs = null; + for (File f : File.listRoots()) { + FileObject fo = FileUtil.toFileObject(f); + if (fo != null) { + try { + fs = fo.getFileSystem(); + break; + } catch (FileStateInvalidException ex) { + LOG.log(Level.WARNING, "Cannot find filesystem for " + f, ex); // NOI18N + } + } + } + + if (fs != null) { + try { + fs.runAtomicAction(new FileSystem.AtomicAction() { + public void run() throws IOException { + command.run(); + } + }); + } catch (IOException ex) { + throw (IllegalStateException)new IllegalStateException().initCause(ex); + } + } else { + command.run(); + } + } + }; + private static final Mutex MUTEX = new Mutex(new Mutex.Privileged(), FS_EXEC); /** * Get a read/write lock to be used for all project metadata accesses. * All methods relating to recognizing and loading projects, saving them, Index: projects/projectapi/test/unit/src/org/netbeans/api/project/ProjectManagerTest.java --- projects/projectapi/test/unit/src/org/netbeans/api/project/ProjectManagerTest.java Base (1.15) +++ projects/projectapi/test/unit/src/org/netbeans/api/project/ProjectManagerTest.java Locally Modified (Based On 1.15) @@ -51,7 +51,12 @@ import java.util.logging.Level; import org.netbeans.junit.NbTestCase; import org.netbeans.modules.projectapi.TimedWeakReference; +import org.openide.filesystems.FileAttributeEvent; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileRenameEvent; +import org.openide.util.Mutex; import org.openide.util.test.MockLookup; /* XXX tests needed: @@ -67,7 +72,8 @@ * Test ProjectManager find and save functionality. * @author Jesse Glick */ -public class ProjectManagerTest extends NbTestCase { +public class ProjectManagerTest extends NbTestCase +implements FileChangeListener { static { // For easier testing. @@ -92,6 +98,9 @@ protected void setUp() throws Exception { super.setUp(); scratch = TestUtil.makeScratchDir(this); + + scratch.getFileSystem().addFileChangeListener(this); + goodproject = scratch.createFolder("good"); goodproject.createFolder("testproject"); goodproject2 = scratch.createFolder("good2"); @@ -106,6 +115,8 @@ } protected void tearDown() throws Exception { + scratch.getFileSystem().removeFileChangeListener(this); + scratch = null; goodproject = null; badproject = null; @@ -343,6 +354,22 @@ assertNotNull("now p3 is recognized as a non-broken project", pm.findProject(p3)); assertEquals("p1 still recognized as a project", proj1, pm.findProject(p1)); } + public void testClearNonProjectCacheInWriteAccess() throws Exception { + ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction() { + public Void run() throws Exception { + testClearNonProjectCache(); + return null; + } + }); + } + public void testClearNonProjectCacheInReadAccess() throws Exception { + ProjectManager.mutex().readAccess(new Mutex.ExceptionAction() { + public Void run() throws Exception { + testClearNonProjectCache(); + return null; + } + }); + } public void testLoadExceptionWithConcurrentLoad() throws Exception { TestUtil.BROKEN_PROJECT_LOAD_LOCK = new Object(); @@ -473,4 +500,32 @@ assertTrue("An IllegalStateException was thrown when calling notifyDeleted twice.", wasException); } + private void assertNoAccess() { + assertFalse("No read access", ProjectManager.mutex().isReadAccess()); + assertFalse("No write access", ProjectManager.mutex().isWriteAccess()); } + + public void fileFolderCreated(FileEvent fe) { + assertNoAccess(); + } + + public void fileDataCreated(FileEvent fe) { + assertNoAccess(); + } + + public void fileChanged(FileEvent fe) { + assertNoAccess(); + } + + public void fileDeleted(FileEvent fe) { + assertNoAccess(); + } + + public void fileRenamed(FileRenameEvent fe) { + assertNoAccess(); + } + + public void fileAttributeChanged(FileAttributeEvent fe) { + assertNoAccess(); + } +}