diff -r 30a77a190a8d openide.filesystems/src/org/openide/filesystems/EventControl.java --- a/openide.filesystems/src/org/openide/filesystems/EventControl.java Wed Aug 05 12:27:49 2009 -0400 +++ b/openide.filesystems/src/org/openide/filesystems/EventControl.java Wed Aug 05 22:20:35 2009 +0200 @@ -42,7 +42,9 @@ package org.openide.filesystems; import java.io.IOException; +import java.util.LinkedHashSet; import java.util.LinkedList; +import java.util.Set; /** * @author rmatous @@ -197,15 +199,18 @@ private LinkedList invokeDispatchers(boolean priority, LinkedList reqQueueCopy) { LinkedList newEnum = new LinkedList(); - + Set postNotify = new LinkedHashSet(); while ((reqQueueCopy != null) && !reqQueueCopy.isEmpty()) { FileSystem.EventDispatcher r = reqQueueCopy.removeFirst(); - r.dispatch(priority); + r.dispatch(priority, postNotify); if (priority) { newEnum.add(r); } } + for (Runnable r : postNotify) { + r.run(); + } return newEnum; } @@ -214,7 +219,7 @@ private synchronized boolean postponeFiring(FileSystem.EventDispatcher disp) { if (priorityRequests == 0) { disp.setAtomicActionLink(currentAtomAction); - disp.dispatch(true); + disp.dispatch(true, null); } if (requestsQueue != null) { diff -r 30a77a190a8d openide.filesystems/src/org/openide/filesystems/FCLSupport.java --- a/openide.filesystems/src/org/openide/filesystems/FCLSupport.java Wed Aug 05 12:27:49 2009 -0400 +++ b/openide.filesystems/src/org/openide/filesystems/FCLSupport.java Wed Aug 05 22:20:35 2009 +0200 @@ -40,8 +40,11 @@ */ package org.openide.filesystems; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import org.openide.util.Exceptions; import org.openide.util.RequestProcessor; @@ -77,7 +80,7 @@ } } - final void dispatchEvent(FileEvent fe, Op operation) { + final void dispatchEvent(FileEvent fe, Op operation, Collection postNotify) { List fcls; synchronized (this) { @@ -89,14 +92,14 @@ } for (FileChangeListener l : fcls) { - dispatchEvent(l, fe, operation); + dispatchEvent(l, fe, operation, postNotify); } } - final static void dispatchEvent(final FileChangeListener fcl, final FileEvent fe, final Op operation) { + final static void dispatchEvent(final FileChangeListener fcl, final FileEvent fe, final Op operation, Collection postNotify) { boolean async = fe.isAsynchronous(); DispatchEventWrapper dw = new DispatchEventWrapper(fcl, fe, operation); - dw.dispatchEvent(async); + dw.dispatchEvent(async, postNotify); } /** @return true if there is a listener @@ -114,17 +117,18 @@ this.fe =fe; this.operation =operation; } - void dispatchEvent(boolean async) { + void dispatchEvent(boolean async, Collection postNotify) { if (async) { q.offer(this); task.schedule(300); } else { - dispatchEventImpl(fcl, fe, operation); + dispatchEventImpl(fcl, fe, operation, postNotify); } } - private void dispatchEventImpl(FileChangeListener fcl, FileEvent fe, Op operation) { + private void dispatchEventImpl(FileChangeListener fcl, FileEvent fe, Op operation, Collection postNotify) { try { + fe.setPostNotify(postNotify); switch (operation) { case DATA_CREATED: fcl.fileDataCreated(fe); @@ -149,6 +153,8 @@ } } catch (RuntimeException x) { Exceptions.printStackTrace(x); + } finally { + fe.setPostNotify(null); } } @@ -158,10 +164,14 @@ private static RequestProcessor.Task task = RP.create(new Runnable() { public void run() { DispatchEventWrapper dw = q.poll(); + Set post = new HashSet(); while (dw != null) { - dw.dispatchEvent(false); + dw.dispatchEvent(false, post); dw = q.poll(); } + for (Runnable r : post) { + r.run(); + } } }); } diff -r 30a77a190a8d openide.filesystems/src/org/openide/filesystems/FileEvent.java --- a/openide.filesystems/src/org/openide/filesystems/FileEvent.java Wed Aug 05 12:27:49 2009 -0400 +++ b/openide.filesystems/src/org/openide/filesystems/FileEvent.java Wed Aug 05 22:20:35 2009 +0200 @@ -41,6 +41,7 @@ package org.openide.filesystems; +import java.util.Collection; import java.util.Date; import java.util.EventObject; @@ -66,6 +67,7 @@ /***/ private EventControl.AtomicActionLink atomActionID; + private transient Collection postNotify; /** Creates new FileEvent. The FileObject where the action occurred * is assumed to be the same as the source object. @@ -135,6 +137,15 @@ return expected; } + public final void runWhenDeliveryOver(Runnable r) { + Collection to = postNotify; + if (to != null) { + to.add(r); + } else { + r.run(); + } + } + @Override public String toString() { StringBuilder b = new StringBuilder(); @@ -198,5 +209,11 @@ return false; } + + void setPostNotify(Collection runs) { + // cannot try to set the postNotify field twiced + assert postNotify == null || runs == null; + this.postNotify = runs; + } } diff -r 30a77a190a8d openide.filesystems/src/org/openide/filesystems/FileObject.java --- a/openide.filesystems/src/org/openide/filesystems/FileObject.java Wed Aug 05 12:27:49 2009 -0400 +++ b/openide.filesystems/src/org/openide/filesystems/FileObject.java Wed Aug 05 22:20:35 2009 +0200 @@ -996,7 +996,7 @@ /** @param onlyPriority if true then invokes only priority listeners * else all listeners are invoked. */ - protected void dispatch(boolean onlyPriority) { + protected void dispatch(boolean onlyPriority, Collection postNotify) { if (this.op == null) { this.op = fe.getFile().isFolder() ? FCLSupport.Op.FOLDER_CREATED : FCLSupport.Op.DATA_CREATED; } @@ -1011,7 +1011,7 @@ continue; } - FCLSupport.dispatchEvent(fcl, fe, op); + FCLSupport.dispatchEvent(fcl, fe, op, postNotify); } if (onlyPriority) { @@ -1049,14 +1049,14 @@ } if (fs != null && fsList != null) { for (FileChangeListener fcl : fsList) { - FCLSupport.dispatchEvent(fcl, fe, op); + FCLSupport.dispatchEvent(fcl, fe, op, postNotify); } } if (rep != null && repList != null) { for (FileChangeListener fcl : repList) { - FCLSupport.dispatchEvent(fcl, fe, op); + FCLSupport.dispatchEvent(fcl, fe, op, postNotify); } } } diff -r 30a77a190a8d openide.filesystems/src/org/openide/filesystems/FileSystem.java --- a/openide.filesystems/src/org/openide/filesystems/FileSystem.java Wed Aug 05 12:27:49 2009 -0400 +++ b/openide.filesystems/src/org/openide/filesystems/FileSystem.java Wed Aug 05 22:20:35 2009 +0200 @@ -49,6 +49,7 @@ import java.beans.VetoableChangeListener; import java.io.IOException; import java.io.Serializable; +import java.util.Collection; import java.util.List; import java.util.Set; import org.openide.util.Exceptions; @@ -877,13 +878,13 @@ */ static abstract class EventDispatcher extends Object implements Runnable { public final void run() { - dispatch(false); + dispatch(false, null); } /** @param onlyPriority if true then invokes only priority listeners * else all listeners are invoked. */ - protected abstract void dispatch(boolean onlyPriority); + protected abstract void dispatch(boolean onlyPriority, Collection postNotify); /** @param propID */ protected abstract void setAtomicActionLink(EventControl.AtomicActionLink propID); @@ -898,7 +899,7 @@ this.fStatusEvent = fStatusEvent; } - protected void dispatch(boolean onlyPriority) { + protected void dispatch(boolean onlyPriority, Collection postNotify) { if (onlyPriority) { return; } diff -r 30a77a190a8d openide.filesystems/test/unit/src/org/openide/filesystems/AtomicActionTest.java --- a/openide.filesystems/test/unit/src/org/openide/filesystems/AtomicActionTest.java Wed Aug 05 12:27:49 2009 -0400 +++ b/openide.filesystems/test/unit/src/org/openide/filesystems/AtomicActionTest.java Wed Aug 05 22:20:35 2009 +0200 @@ -94,6 +94,7 @@ } }); assertTrue(tcl.deleteNotification); + assertTrue("Notified about end of delivery", tcl.over); tcl.reset(); assertNotNull(FileUtil.createData(root, "data")); @@ -116,16 +117,27 @@ } }); assertTrue(tcl.deleteNotification); + assertTrue("Notified about end of delivery", tcl.over); } - private static class TestChangeListener extends FileChangeAdapter { + private static class TestChangeListener extends FileChangeAdapter + implements Runnable { private boolean deleteNotification; + private boolean over; @Override public void fileDeleted(FileEvent fe) { + assertFalse("Delivery of events is not over yet", over); deleteNotification = true; + fe.runWhenDeliveryOver(this); } public void reset() { deleteNotification = false; + over = false; + } + + public void run() { + assertFalse("Over not set yet", over); + over = true; } } } diff -r 30a77a190a8d openide.filesystems/test/unit/src/org/openide/filesystems/FileObjectTestHid.java --- a/openide.filesystems/test/unit/src/org/openide/filesystems/FileObjectTestHid.java Wed Aug 05 12:27:49 2009 -0400 +++ b/openide.filesystems/test/unit/src/org/openide/filesystems/FileObjectTestHid.java Wed Aug 05 22:20:35 2009 +0200 @@ -183,22 +183,34 @@ fail(); } }; + class Once implements Runnable { + int once; + + public void run() { + assertEquals("No calls yet", 0, once); + once++; + } + } + final Once post = new Once(); final FileChangeListener listener1 = new FileChangeAdapter(){ @Override public void fileDataCreated(FileEvent fe) { fold.removeFileChangeListener(noFileDataCreatedListener); fold.addFileChangeListener(noFileDataCreatedListener); + fe.runWhenDeliveryOver(post); } }; - + assertEquals("Not called yet", 0, post.once); try { fold.getFileSystem().addFileChangeListener(listener1); fold.getFileSystem().runAtomicAction(new FileSystem.AtomicAction(){ public void run() throws java.io.IOException { fold.createData("file1"); fold.createData("file2"); + assertEquals("Called not", 0, post.once); } }); + assertEquals("Called once", 1, post.once); } finally { fold.getFileSystem().removeFileChangeListener(listener1); fold.removeFileChangeListener(noFileDataCreatedListener); @@ -993,6 +1005,30 @@ registerDefaultListener(testedFS); FileLock lock = null; + class Immediate extends FileChangeAdapter implements Runnable { + int cnt; + FileRenameEvent fe; + @Override + public void fileRenamed(FileRenameEvent fe) { + int prev = cnt; + fe.runWhenDeliveryOver(this); + assertEquals("run() not called immediatelly", prev, cnt); + this.fe = fe; + } + public void run() { + cnt++; + } + + void testCallOutsideOfDeliverySystem() { + assertNotNull("There shall be an event", fe); + int prev = cnt; + fe.runWhenDeliveryOver(this); + assertEquals("run() called immediatelly", prev + 1, cnt); + } + } + Immediate immediatelly = new Immediate(); + fo.addFileChangeListener(immediatelly); + try { lock = fo.lock(); fo.rename(lock,fo.getName()+"X",fo.getExt()+"X"); @@ -1004,6 +1040,8 @@ } finally { if (lock != null) lock.releaseLock(); } + assertEquals("One call", 1, immediatelly.cnt); + immediatelly.testCallOutsideOfDeliverySystem(); fileRenamedAssert("",1); fileDataCreatedAssert("fireFileDataCreatedEvent should not be fired ",0);