This is an automated email from the ASF dual-hosted git repository. ecki pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-vfs.git
The following commit(s) were added to refs/heads/master by this push: new 709d099c [VFS-853] Fix FileListener on DelegateFileObject. 709d099c is described below commit 709d099ce6bb98f1c781e18c9e211304188ce260 Author: Bernd Eckenfels <e...@apache.org> AuthorDate: Mon May 27 17:25:57 2024 +0200 [VFS-853] Fix FileListener on DelegateFileObject. This adds a new test JunctionTests#testEvent() which fails when the fix is not present. --- .../commons/vfs2/util/WeakRefFileListener.java | 15 ++++- .../commons/vfs2/provider/test/JunctionTests.java | 77 ++++++++++++++++++++++ src/changes/changes.xml | 3 + 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/WeakRefFileListener.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/WeakRefFileListener.java index 99e2303c..05c989f1 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/WeakRefFileListener.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/WeakRefFileListener.java @@ -32,13 +32,24 @@ import org.apache.commons.vfs2.FileSystem; public class WeakRefFileListener implements FileListener { /** - * Installs the {@code listener} at the given {@code file}. + * Install the {@code listener} at the given {@code file}. + * <p> + * This installs a wrapper with a weak reference, so the listener can + * be collected. The reference to the listener is removed when the + * first event can't be delivered. + * <p> + * Warning: you cannot remove the listener with + * {@code fs.removeListener(file, listener)} as you do'nt have the wrapper + * instance at hand. + * <p> + * Method is used by {@link org.apache.commons.vfs2.provider.DelegateFileObject}, + * as used for {@link org.apache.commons.vfs2.impl.VirtualFileSystem}. * * @param file The FileObject to listen on. * @param listener The FileListener */ public static void installListener(final FileObject file, final FileListener listener) { - file.getFileSystem().addListener(file, new WeakRefFileListener(file, new WeakRefFileListener(file, listener))); + file.getFileSystem().addListener(file, new WeakRefFileListener(file, listener)); } private final FileSystem fs; diff --git a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/test/JunctionTests.java b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/test/JunctionTests.java index 41bc76b9..9099b67c 100644 --- a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/test/JunctionTests.java +++ b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/test/JunctionTests.java @@ -22,9 +22,13 @@ import static org.apache.commons.vfs2.VfsTestUtils.getTestDirectoryFile; import java.io.File; import org.apache.commons.vfs2.AbstractProviderTestCase; +import org.apache.commons.vfs2.FileChangeEvent; +import org.apache.commons.vfs2.FileListener; import org.apache.commons.vfs2.FileObject; import org.apache.commons.vfs2.FileSystem; import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.provider.DelegateFileObject; +import org.apache.commons.vfs2.util.WeakRefFileListener; import org.junit.Test; /** @@ -92,6 +96,52 @@ public class JunctionTests extends AbstractProviderTestCase { } } + /** + * Checks that change events from delegatedd files are fired. + */ + public void testEvent() throws Exception { + // we use the VirtualFileSystem to check change event propagation of DecoratedFileObject + final FileSystem fs = getManager().createVirtualFileSystem("vfs://").getFileSystem(); + final FileObject baseDir = getBaseDir().resolveFile("junctiontest"); + + // Add the junction + fs.addJunction("/a", baseDir); + + // Make sure the file at the junction point and its ancestors exist + FileObject file = fs.resolveFile("/a/hardref.txt"); + assertSame("VirtualFileSystem does not use DelegateFO anymore?", file.getClass(), DelegateFileObject.class); + + // Do with a hard reference listener + FileListener listener1 = new DebugFileListener(); + file.getFileSystem().addListener(file, listener1); + FileObject real1 = baseDir.resolveFile("hardref.txt"); + real1.createFile(); + assertEquals("Strong Listener was not notified (create)", "Listener false true false", listener1.toString()); + real1.delete(); + assertEquals("Strong Listener was not notified (delete)", "Listener false true true", listener1.toString()); + + FileObject file2 = fs.resolveFile("/a/weakref.txt"); + assertSame("VirtualFileSystem does not use DelegateFO anymore?", file2.getClass(), DelegateFileObject.class); + // repeat with Weak reference listener + FileListener listener2 = new DebugFileListener(); + // since we hold the listener2 reference it should not get GC + WeakRefFileListener.installListener(file2, listener2); + + // force the WekRefFileListener reference to (not) clear + System.gc(); + Thread.sleep(1000); + System.gc(); + Thread.sleep(1000); + System.gc(); + Thread.sleep(1000); + System.gc(); + Thread.sleep(1000); + + FileObject real2 = baseDir.resolveFile("weakref.txt"); + real2.createFile(); + assertEquals("Weak Listener was abandoned", "Listener false true false", listener2.toString()); + } + // Check that file @ junction point exists only when backing file exists // Add 2 junctions with common parent // Compare real and virtual files @@ -99,3 +149,30 @@ public class JunctionTests extends AbstractProviderTestCase { // Remove junctions } + +class DebugFileListener implements FileListener { + private boolean changed; + private boolean created; + private boolean deleted; + + @Override + public void fileChanged(FileChangeEvent event) throws Exception { + changed = true; + } + + @Override + public void fileCreated(FileChangeEvent event) throws Exception { + created = true; + } + + @Override + public void fileDeleted(FileChangeEvent event) throws Exception { + deleted = true; + } + + @Override + public String toString() { + return "Listener " + changed + " " + created + " " + deleted; + } +} // class DebugListener + diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 6e529c61..79932deb 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -47,6 +47,9 @@ The <action> type attribute can be add,update,fix,remove. <body> <release version="2.10.0" date="YYYY-MM-DD" description="Maintenance release. Requires Java 8 or above."> <!-- FIX --> + <action type="fix" issue="VFS-853" dev="ecki" due-to="Bernd Eckenfels"> + Double wrapped weak FileListener can lose change notification with DelegateFileObject. + </action> <action type="fix" dev="ggregory" due-to="Seth Falco"> Replace package.html with package-info.java #206. </action>