This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 180523
Collapse All | Expand All

(-)a/masterfs/nbproject/project.xml (-1 / +1 lines)
Lines 60-66 Link Here
60
                    <build-prerequisite/>
60
                    <build-prerequisite/>
61
                    <compile-dependency/>
61
                    <compile-dependency/>
62
                    <run-dependency>
62
                    <run-dependency>
63
                        <specification-version>7.28</specification-version>
63
                        <specification-version>7.37</specification-version>
64
                    </run-dependency>
64
                    </run-dependency>
65
                </dependency>
65
                </dependency>
66
                <dependency>
66
                <dependency>
(-)a/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileObjectKeeper.java (-2 / +17 lines)
Lines 44-49 Link Here
44
import java.util.Enumeration;
44
import java.util.Enumeration;
45
import java.util.HashSet;
45
import java.util.HashSet;
46
import java.util.Set;
46
import java.util.Set;
47
import java.util.concurrent.Callable;
47
import java.util.concurrent.CopyOnWriteArraySet;
48
import java.util.concurrent.CopyOnWriteArraySet;
48
import java.util.logging.Level;
49
import java.util.logging.Level;
49
import java.util.logging.Logger;
50
import java.util.logging.Logger;
Lines 74-80 Link Here
74
            listeners = new CopyOnWriteArraySet<FileChangeListener>();
75
            listeners = new CopyOnWriteArraySet<FileChangeListener>();
75
        }
76
        }
76
        if (listeners.isEmpty()) {
77
        if (listeners.isEmpty()) {
77
            listenToAll();
78
            Callable<?> stop = null;
79
            if (fcl instanceof Callable && fcl.getClass().getName().equals("org.openide.filesystems.DeepListener")) { // NOI18N
80
                stop = (Callable<?>)fcl;
81
            }
82
            listenToAll(stop);
78
        }
83
        }
79
        listeners.add(fcl);
84
        listeners.add(fcl);
80
    }
85
    }
Lines 123-129 Link Here
123
        LOG.log(Level.FINE, "Testing {0}, time {1}", new Object[] { file, timeStamp });
128
        LOG.log(Level.FINE, "Testing {0}, time {1}", new Object[] { file, timeStamp });
124
    }
129
    }
125
130
126
    private final void listenToAll() {
131
    private final void listenToAll(Callable<?> stop) {
127
        assert Thread.holdsLock(this);
132
        assert Thread.holdsLock(this);
128
        assert kept == null;
133
        assert kept == null;
129
        kept = new HashSet<FileObject>();
134
        kept = new HashSet<FileObject>();
Lines 133-138 Link Here
133
            FileObject fo = en.nextElement();
138
            FileObject fo = en.nextElement();
134
            if (fo instanceof FolderObj) {
139
            if (fo instanceof FolderObj) {
135
                FolderObj obj = (FolderObj)fo;
140
                FolderObj obj = (FolderObj)fo;
141
                Object shallStop = null;
142
                if (stop != null) try {
143
                    shallStop = stop.call();
144
                } catch (Exception ex) {
145
                    shallStop = Boolean.TRUE;
146
                }
147
                if (Boolean.TRUE.equals(shallStop)) {
148
                    LOG.log(Level.INFO, "addRecursiveListener to {0} interrupted", root); // NOI18N
149
                    return;
150
                }
136
                obj.addFileChangeListener(this);
151
                obj.addFileChangeListener(this);
137
                kept.add(obj);
152
                kept.add(obj);
138
                obj.getKeeper();
153
                obj.getKeeper();
(-)a/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FolderObj.java (+2 lines)
Lines 53-58 Link Here
53
import java.util.List;
53
import java.util.List;
54
import java.util.Map;
54
import java.util.Map;
55
import java.util.Set;
55
import java.util.Set;
56
import java.util.concurrent.Callable;
56
import java.util.logging.Level;
57
import java.util.logging.Level;
57
import java.util.logging.LogRecord;
58
import java.util.logging.LogRecord;
58
import java.util.logging.Logger;
59
import java.util.logging.Logger;
Lines 69-74 Link Here
69
import org.openide.filesystems.FileChangeListener;
70
import org.openide.filesystems.FileChangeListener;
70
import org.openide.filesystems.FileLock;
71
import org.openide.filesystems.FileLock;
71
import org.openide.filesystems.FileObject;
72
import org.openide.filesystems.FileObject;
73
import org.openide.util.Exceptions;
72
import org.openide.util.Mutex;
74
import org.openide.util.Mutex;
73
75
74
/**
76
/**
(-)a/openide.filesystems/apichanges.xml (+17 lines)
Lines 46-51 Link Here
46
        <apidef name="filesystems">Filesystems API</apidef>
46
        <apidef name="filesystems">Filesystems API</apidef>
47
    </apidefs>
47
    </apidefs>
48
    <changes>
48
    <changes>
49
        <change id="addRecursiveListenerStop">
50
            <api name="filesystems"/>
51
            <summary>Interruptable addRecursiveListener</summary>
52
            <version major="7" minor="37"/>
53
            <date day="17" month="2" year="2010"/>
54
            <author login="jtulach"/>
55
            <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
56
            <description>
57
                <p>
58
                    New variant of <code>addRecursiveListener</code> method
59
                    that allows the caller to control the process enumerating
60
                    files in subtree and stop it.
61
                </p>
62
            </description>
63
            <class package="org.openide.filesystems" name="FileUtil"/>
64
            <issue number="180523"/>
65
        </change>
49
        <change id="MultiFileSystem.weight">
66
        <change id="MultiFileSystem.weight">
50
            <api name="filesystems"/>
67
            <api name="filesystems"/>
51
            <summary>Ability to specify "weight" for <code>MultiFileSystem</code> overrides</summary>
68
            <summary>Ability to specify "weight" for <code>MultiFileSystem</code> overrides</summary>
(-)a/openide.filesystems/manifest.mf (-1 / +1 lines)
Lines 2-6 Link Here
2
OpenIDE-Module: org.openide.filesystems
2
OpenIDE-Module: org.openide.filesystems
3
OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties
4
OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml
4
OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml
5
OpenIDE-Module-Specification-Version: 7.36
5
OpenIDE-Module-Specification-Version: 7.37
6
6
(-)a/openide.filesystems/src/org/openide/filesystems/DeepListener.java (-2 / +9 lines)
Lines 45-50 Link Here
45
import java.util.Collections;
45
import java.util.Collections;
46
import java.util.List;
46
import java.util.List;
47
import java.util.Set;
47
import java.util.Set;
48
import java.util.concurrent.Callable;
48
import org.openide.util.Utilities;
49
import org.openide.util.Utilities;
49
import org.openide.util.WeakSet;
50
import org.openide.util.WeakSet;
50
51
Lines 53-67 Link Here
53
 * @author Jaroslav Tulach <jtulach@netbeans.org>
54
 * @author Jaroslav Tulach <jtulach@netbeans.org>
54
 */
55
 */
55
final class DeepListener extends WeakReference<FileChangeListener>
56
final class DeepListener extends WeakReference<FileChangeListener>
56
implements FileChangeListener, Runnable {
57
implements FileChangeListener, Runnable, Callable<Boolean> {
57
    private final File path;
58
    private final File path;
58
    private FileObject watching;
59
    private FileObject watching;
59
    private boolean removed;
60
    private boolean removed;
61
    private final Callable<Boolean> stop;
60
    private static List<DeepListener> keep = new ArrayList<DeepListener>();
62
    private static List<DeepListener> keep = new ArrayList<DeepListener>();
61
63
62
    public DeepListener(FileChangeListener listener, File path) {
64
    DeepListener(FileChangeListener listener, File path, Callable<Boolean> stop) {
63
        super(listener, Utilities.activeReferenceQueue());
65
        super(listener, Utilities.activeReferenceQueue());
64
        this.path = path;
66
        this.path = path;
67
        this.stop = stop;
65
        relisten();
68
        relisten();
66
        keep.add(this);
69
        keep.add(this);
67
    }
70
    }
Lines 199-202 Link Here
199
        return get();
202
        return get();
200
    }
203
    }
201
204
205
    @Override
206
    public Boolean call() throws Exception {
207
        return stop != null ? stop.call() : null;
208
    }
202
}
209
}
(-)a/openide.filesystems/src/org/openide/filesystems/FileUtil.java (-2 / +50 lines)
Lines 67-72 Link Here
67
import java.util.Stack;
67
import java.util.Stack;
68
import java.util.StringTokenizer;
68
import java.util.StringTokenizer;
69
import java.util.WeakHashMap;
69
import java.util.WeakHashMap;
70
import java.util.concurrent.Callable;
70
import java.util.jar.JarEntry;
71
import java.util.jar.JarEntry;
71
import java.util.jar.JarInputStream;
72
import java.util.jar.JarInputStream;
72
import java.util.logging.Level;
73
import java.util.logging.Level;
Lines 333-339 Link Here
333
     * @since org.openide.filesystems 7.28
334
     * @since org.openide.filesystems 7.28
334
     */
335
     */
335
    public static void addRecursiveListener(FileChangeListener listener, File path) {
336
    public static void addRecursiveListener(FileChangeListener listener, File path) {
336
        addFileChangeListener(new DeepListener(listener, path), path);
337
        addFileChangeListener(new DeepListener(listener, path, null), path);
338
    }
339
340
    /**
341
     * Adds a listener to changes under given path. It permits you to listen to a file
342
     * which does not yet exist, or continue listening to it after it is deleted and recreated, etc.
343
     * <br/>
344
     * When given path represents a file ({@code path.isDirectory() == false}), this
345
     * code behaves exectly like {@link #addFileChangeListener(org.openide.filesystems.FileChangeListener, java.io.File)}.
346
     * Usually the path shall represent a folder ({@code path.isDirectory() == true})
347
     * <ul>
348
     * <li>fileFolderCreated event is fired when the folder is created or a child folder created</li>
349
     * <li>fileDataCreated event is fired when a child file is created</li>
350
     * <li>fileDeleted event is fired when the folder is deleted or a child file/folder removed</li>
351
     * <li>fileChanged event is fired when a child file is modified</li>
352
     * <li>fileRenamed event is fired when the folder is renamed or a child file/folder is renamed</li>
353
     * <li>fileAttributeChanged is fired when FileObject's attribute is changed</li>
354
     *</ul>
355
     * The above events are delivered for changes in all subdirectories (recursively).
356
     * It is guaranteed that with each change at least one event is generated.
357
     * For example adding a folder does not notify about content of the folder,
358
     * hence one event is delivered.
359
     *
360
     * Can only add a given [listener, path] pair once. However a listener can
361
     * listen to any number of paths. Note that listeners are always held weakly
362
     * - if the listener is collected, it is quietly removed.
363
     *
364
     * <div class="nonnormative">
365
     * As registering of the listener can take a long time, especially on deep
366
     * hierarchies, it is possible provide a callback <code>stop</code>.
367
     * This stop object is guaranteed to be called once per every folder on the
368
     * default (when masterfs module is included) implemention. If the call
369
     * to <code>stop.call()</code> returns true, then the registration of
370
     * next recursive items is interrupted. The listener may or may not get
371
     * some events from already registered folders.
372
     * </div>
373
     *
374
     * @param listener FileChangeListener to listen to changes in path
375
     * @param path File path to listen to (even not existing)
376
     * @param stop an interface to interrupt the process of registering
377
     *    the listener. If the <code>call</code> returns true, the process
378
     *    of registering the listener is immediately interrupted
379
     *
380
     * @see FileObject#addRecursiveListener
381
     * @since org.openide.filesystems 7.37
382
     */
383
    public static void addRecursiveListener(FileChangeListener listener, File path, Callable<Boolean> stop) {
384
        addFileChangeListener(new DeepListener(listener, path, stop), path);
337
    }
385
    }
338
386
339
    /**
387
    /**
Lines 346-352 Link Here
346
     * @since org.openide.filesystems 7.28
394
     * @since org.openide.filesystems 7.28
347
     */
395
     */
348
    public static void removeRecursiveListener(FileChangeListener listener, File path) {
396
    public static void removeRecursiveListener(FileChangeListener listener, File path) {
349
        DeepListener dl = (DeepListener)removeFileChangeListenerImpl(new DeepListener(listener, path), path);
397
        DeepListener dl = (DeepListener)removeFileChangeListenerImpl(new DeepListener(listener, path, null), path);
350
        dl.run();
398
        dl.run();
351
    }
399
    }
352
400

Return to bug 180523