--- a/openide.loaders/src/org/openide/loaders/DataNode.java +++ a/openide.loaders/src/org/openide/loaders/DataNode.java @@ -45,6 +45,7 @@ package org.openide.loaders; +import java.awt.EventQueue; import java.awt.datatransfer.*; import java.beans.*; import java.io.*; @@ -758,6 +759,20 @@ * @param ev event describing the change */ void fireChange(final PropertyChangeEvent ev) { + // If the DataObject is not valid the node should be + // removed. Called always asynchronously, see bug 232085. + if (DataObject.PROP_VALID.equals(ev.getPropertyName())) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + Object newVal = ev.getNewValue(); + if ((newVal instanceof Boolean) && (!((Boolean) newVal).booleanValue())) { + fireNodeDestroyed(); + } + } + }); + return; + } Mutex.EVENT.writeAccess(new Runnable() { public void run() { @@ -786,16 +801,6 @@ //return; } - // if the DataOjbect is not valid the node should be - // removed - if (DataObject.PROP_VALID.equals(ev.getPropertyName())) { - Object newVal = ev.getNewValue(); - if ((newVal instanceof Boolean) && (!((Boolean) newVal).booleanValue())) { - fireNodeDestroyed(); - } - return; - } - /*See #31413*/ List transmitProperties = Arrays.asList(new String[] { DataObject.PROP_NAME, DataObject.PROP_FILES, DataObject.PROP_TEMPLATE}); --- a/openide.loaders/test/unit/src/org/openide/loaders/DataNodeTest.java +++ a/openide.loaders/test/unit/src/org/openide/loaders/DataNodeTest.java @@ -44,10 +44,13 @@ package org.openide.loaders; +import java.awt.EventQueue; import java.io.IOException; import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationTargetException; import java.util.Enumeration; import java.util.Set; +import java.util.concurrent.Semaphore; import java.util.logging.Level; import java.util.logging.Logger; import org.netbeans.junit.NbTestCase; @@ -59,7 +62,10 @@ import org.openide.filesystems.FileUtil; import org.openide.nodes.Children; import org.openide.nodes.Node; +import org.openide.nodes.NodeAdapter; +import org.openide.nodes.NodeEvent; import org.openide.util.Enumerations; +import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.lookup.Lookups; import org.openide.util.test.MockLookup; @@ -235,6 +241,55 @@ assertGC("DataObject released", refD); } + /** + * Test for bug 232085. + * + * @throws IOException + * @throws InterruptedException + * @throws InvocationTargetException + */ + public void testDestroyedEventNotFiredUnderPoolLock() throws IOException, + InterruptedException, InvocationTargetException { + + final FileSystem fs = FileUtil.createMemoryFileSystem(); + final FileObject fob = fs.getRoot().createData("file.txt"); + final DataObject dob = DataObject.find(fob); + final Node n = dob.getNodeDelegate(); + final Semaphore s = new Semaphore(0); + final boolean[] underLock = new boolean[]{true}; + + n.addNodeListener(new NodeAdapter() { + + @Override + public void nodeDestroyed(NodeEvent ev) { + underLock[0] = DataObjectPool.isConstructorAllowed(); + s.release(); + } + }); + + EventQueue.invokeAndWait(new Runnable() { + + @Override + public void run() { + try { + DataObjectPool.getPOOL().runAtomicAction(fob, + new FileSystem.AtomicAction() { + + @Override + public void run() throws IOException { + dob.delete(); + } + }); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + }); + s.acquire(); + assertFalse("NodeDestroyed event fired from DataObjectPool's " + + "'allow constructor' mode.", underLock[0]); + } + private static final class FSWithStatus extends org.openide.filesystems.LocalFileSystem implements FileSystem.HtmlStatus { public Set lastFiles;