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 170544
Collapse All | Expand All

(-)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="runWhenDeliveryOver">
50
            <api name="filesystems"/>
51
            <summary>Support for processing batch events</summary>
52
            <version major="7" minor="24"/>
53
            <date day="25" month="8" year="2009"/>
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
                    <a href="org/openide/filesystems/FileEvent.html#runWhenDeliveryOver(java.lang.Runnable)">
59
                    FileEvent.runWhenDeliveryOver(Runnable)</a> method added to support
60
                    easier processing of <em>batch</em> sets of events.
61
                </p>
62
            </description>
63
            <class package="org.openide.filesystems" name="FileEvent"/>
64
            <issue number="170544"/>
65
        </change>
49
         <change id="add-fallback-content-to-sfs">
66
         <change id="add-fallback-content-to-sfs">
50
            <api name="filesystems"/>
67
            <api name="filesystems"/>
51
            <summary>Allow modules to dynamically add/remove layer content</summary>
68
            <summary>Allow modules to dynamically add/remove layer content</summary>
(-)a/openide.filesystems/nbproject/project.properties (-1 / +1 lines)
Lines 44-47 Link Here
44
javadoc.main.page=org/openide/filesystems/doc-files/api.html
44
javadoc.main.page=org/openide/filesystems/doc-files/api.html
45
javadoc.arch=${basedir}/arch.xml
45
javadoc.arch=${basedir}/arch.xml
46
javadoc.apichanges=${basedir}/apichanges.xml
46
javadoc.apichanges=${basedir}/apichanges.xml
47
spec.version.base=7.23.0
47
spec.version.base=7.24.0
(-)a/openide.filesystems/src/org/openide/filesystems/EventControl.java (-3 / +8 lines)
Lines 42-48 Link Here
42
package org.openide.filesystems;
42
package org.openide.filesystems;
43
43
44
import java.io.IOException;
44
import java.io.IOException;
45
import java.util.LinkedHashSet;
45
import java.util.LinkedList;
46
import java.util.LinkedList;
47
import java.util.Set;
46
48
47
/**
49
/**
48
 * @author  rmatous
50
 * @author  rmatous
Lines 197-211 Link Here
197
199
198
    private LinkedList<FileSystem.EventDispatcher> invokeDispatchers(boolean priority, LinkedList<FileSystem.EventDispatcher> reqQueueCopy) {
200
    private LinkedList<FileSystem.EventDispatcher> invokeDispatchers(boolean priority, LinkedList<FileSystem.EventDispatcher> reqQueueCopy) {
199
        LinkedList<FileSystem.EventDispatcher> newEnum = new LinkedList<FileSystem.EventDispatcher>();
201
        LinkedList<FileSystem.EventDispatcher> newEnum = new LinkedList<FileSystem.EventDispatcher>();
200
202
        Set<Runnable> postNotify = new LinkedHashSet<Runnable>();
201
        while ((reqQueueCopy != null) && !reqQueueCopy.isEmpty()) {
203
        while ((reqQueueCopy != null) && !reqQueueCopy.isEmpty()) {
202
            FileSystem.EventDispatcher r = reqQueueCopy.removeFirst();
204
            FileSystem.EventDispatcher r = reqQueueCopy.removeFirst();
203
            r.dispatch(priority);
205
            r.dispatch(priority, postNotify);
204
206
205
            if (priority) {
207
            if (priority) {
206
                newEnum.add(r);
208
                newEnum.add(r);
207
            }
209
            }
208
        }
210
        }
211
        for (Runnable r : postNotify) {
212
            r.run();
213
        }
209
214
210
        return newEnum;
215
        return newEnum;
211
    }
216
    }
Lines 214-220 Link Here
214
    private synchronized boolean postponeFiring(FileSystem.EventDispatcher disp) {
219
    private synchronized boolean postponeFiring(FileSystem.EventDispatcher disp) {
215
        if (priorityRequests == 0) {
220
        if (priorityRequests == 0) {
216
            disp.setAtomicActionLink(currentAtomAction);
221
            disp.setAtomicActionLink(currentAtomAction);
217
            disp.dispatch(true);
222
            disp.dispatch(true, null);
218
        }
223
        }
219
224
220
        if (requestsQueue != null) {
225
        if (requestsQueue != null) {
(-)a/openide.filesystems/src/org/openide/filesystems/FCLSupport.java (-8 / +18 lines)
Lines 40-47 Link Here
40
 */
40
 */
41
package org.openide.filesystems;
41
package org.openide.filesystems;
42
42
43
import java.util.Collection;
44
import java.util.HashSet;
43
import java.util.List;
45
import java.util.List;
44
import java.util.Queue;
46
import java.util.Queue;
47
import java.util.Set;
45
import java.util.concurrent.ConcurrentLinkedQueue;
48
import java.util.concurrent.ConcurrentLinkedQueue;
46
import org.openide.util.Exceptions;
49
import org.openide.util.Exceptions;
47
import org.openide.util.RequestProcessor;
50
import org.openide.util.RequestProcessor;
Lines 77-83 Link Here
77
        }
80
        }
78
    }
81
    }
79
82
80
    final void dispatchEvent(FileEvent fe, Op operation) {
83
    final void dispatchEvent(FileEvent fe, Op operation, Collection<Runnable> postNotify) {
81
        List<FileChangeListener> fcls;
84
        List<FileChangeListener> fcls;
82
85
83
        synchronized (this) {
86
        synchronized (this) {
Lines 89-102 Link Here
89
        }
92
        }
90
93
91
        for (FileChangeListener l : fcls) {
94
        for (FileChangeListener l : fcls) {
92
            dispatchEvent(l, fe, operation);
95
            dispatchEvent(l, fe, operation, postNotify);
93
        }
96
        }
94
    }
97
    }
95
98
96
    final static void dispatchEvent(final FileChangeListener fcl, final FileEvent fe, final Op operation) {
99
    final static void dispatchEvent(final FileChangeListener fcl, final FileEvent fe, final Op operation, Collection<Runnable> postNotify) {
97
        boolean async = fe.isAsynchronous();
100
        boolean async = fe.isAsynchronous();
98
        DispatchEventWrapper dw = new DispatchEventWrapper(fcl, fe, operation);
101
        DispatchEventWrapper dw = new DispatchEventWrapper(fcl, fe, operation);
99
        dw.dispatchEvent(async);
102
        dw.dispatchEvent(async, postNotify);
100
    }
103
    }
101
    
104
    
102
    /** @return true if there is a listener
105
    /** @return true if there is a listener
Lines 114-130 Link Here
114
            this.fe =fe;
117
            this.fe =fe;
115
            this.operation =operation;
118
            this.operation =operation;
116
        }
119
        }
117
        void dispatchEvent(boolean async) {
120
        void dispatchEvent(boolean async, Collection<Runnable> postNotify) {
118
            if (async) {
121
            if (async) {
119
                q.offer(this);
122
                q.offer(this);
120
                task.schedule(300);
123
                task.schedule(300);
121
            } else {
124
            } else {
122
                dispatchEventImpl(fcl, fe, operation);
125
                dispatchEventImpl(fcl, fe, operation, postNotify);
123
            }
126
            }
124
        }        
127
        }        
125
        
128
        
126
        private void dispatchEventImpl(FileChangeListener fcl, FileEvent fe, Op operation) {
129
        private void dispatchEventImpl(FileChangeListener fcl, FileEvent fe, Op operation, Collection<Runnable> postNotify) {
127
            try {
130
            try {
131
                fe.setPostNotify(postNotify);
128
                switch (operation) {
132
                switch (operation) {
129
                    case DATA_CREATED:
133
                    case DATA_CREATED:
130
                        fcl.fileDataCreated(fe);
134
                        fcl.fileDataCreated(fe);
Lines 149-154 Link Here
149
                }
153
                }
150
            } catch (RuntimeException x) {
154
            } catch (RuntimeException x) {
151
                Exceptions.printStackTrace(x);
155
                Exceptions.printStackTrace(x);
156
            } finally {
157
                fe.setPostNotify(null);
152
            }
158
            }
153
        }
159
        }
154
        
160
        
Lines 158-167 Link Here
158
    private static RequestProcessor.Task task = RP.create(new Runnable() {
164
    private static RequestProcessor.Task task = RP.create(new Runnable() {
159
        public void run() {
165
        public void run() {
160
            DispatchEventWrapper dw = q.poll();
166
            DispatchEventWrapper dw = q.poll();
167
            Set<Runnable> post = new HashSet<Runnable>();
161
            while (dw != null) {
168
            while (dw != null) {
162
                dw.dispatchEvent(false);
169
                dw.dispatchEvent(false, post);
163
                dw = q.poll();
170
                dw = q.poll();
164
            }
171
            }
172
            for (Runnable r : post) {
173
                r.run();
174
            }
165
        }
175
        }
166
    });           
176
    });           
167
}
177
}
(-)a/openide.filesystems/src/org/openide/filesystems/FileEvent.java (+35 lines)
Lines 41-46 Link Here
41
41
42
package org.openide.filesystems;
42
package org.openide.filesystems;
43
43
44
import java.util.Collection;
44
import java.util.Date;
45
import java.util.Date;
45
import java.util.EventObject;
46
import java.util.EventObject;
46
47
Lines 66-71 Link Here
66
67
67
    /***/
68
    /***/
68
    private EventControl.AtomicActionLink atomActionID;
69
    private EventControl.AtomicActionLink atomActionID;
70
    private transient Collection<Runnable> postNotify;
69
71
70
    /** Creates new <code>FileEvent</code>. The <code>FileObject</code> where the action occurred
72
    /** Creates new <code>FileEvent</code>. The <code>FileObject</code> where the action occurred
71
    * is assumed to be the same as the source object.
73
    * is assumed to be the same as the source object.
Lines 135-140 Link Here
135
        return expected;
137
        return expected;
136
    }
138
    }
137
139
140
    /** Support for <em>batch</em> processing of events. In some situations
141
     * you may want to delay processing of received events until the last
142
     * known one is delivered. For example if there is a lot of operations
143
     * done inside {@link FileUtil#runAtomicAction(java.lang.Runnable)}
144
     * action, there can be valid reason to do the processing only after
145
     * all of them are delivered. In such situation attach your {@link Runnable}
146
     * to provided event. Such {@link  Runnable} is then guaranteed to be called once.
147
     * Either immediately (if there is no batch delivery in progress)
148
     * or some time later (if there is a batch delivery). You can attach
149
     * single runnable multiple times, even to different events in the
150
     * same batch section and its {@link  Runnable#run()} method will still be
151
     * called just once. {@link Object#equals(java.lang.Object)} is used
152
     * to check equality of two {@link Runnable}s.
153
     *
154
     * @since 7.24
155
     * @param r the runnable to execute when batch event deliver is over
156
     *   (can be even executed immediately)
157
     */
158
    public final void runWhenDeliveryOver(Runnable r) {
159
        Collection<Runnable> to = postNotify;
160
        if (to != null) {
161
            to.add(r);
162
        } else {
163
            r.run();
164
        }
165
    }
166
138
    @Override
167
    @Override
139
    public String toString() {
168
    public String toString() {
140
        StringBuilder b = new StringBuilder();
169
        StringBuilder b = new StringBuilder();
Lines 198-202 Link Here
198
227
199
        return false;
228
        return false;
200
    }
229
    }
230
231
    void setPostNotify(Collection<Runnable> runs) {
232
        // cannot try to set the postNotify field twiced
233
        assert postNotify == null || runs == null;
234
        this.postNotify = runs;
235
    }
201
    
236
    
202
}
237
}
(-)a/openide.filesystems/src/org/openide/filesystems/FileObject.java (-4 / +4 lines)
Lines 996-1002 Link Here
996
        /** @param onlyPriority if true then invokes only priority listeners
996
        /** @param onlyPriority if true then invokes only priority listeners
997
         *  else all listeners are invoked.
997
         *  else all listeners are invoked.
998
         */
998
         */
999
        protected void dispatch(boolean onlyPriority) {
999
        protected void dispatch(boolean onlyPriority, Collection<Runnable> postNotify) {
1000
            if (this.op == null) {
1000
            if (this.op == null) {
1001
                this.op = fe.getFile().isFolder() ? FCLSupport.Op.FOLDER_CREATED : FCLSupport.Op.DATA_CREATED;
1001
                this.op = fe.getFile().isFolder() ? FCLSupport.Op.FOLDER_CREATED : FCLSupport.Op.DATA_CREATED;
1002
            }
1002
            }
Lines 1011-1017 Link Here
1011
1011
1012
                    continue;
1012
                    continue;
1013
                }
1013
                }
1014
                FCLSupport.dispatchEvent(fcl, fe, op);
1014
                FCLSupport.dispatchEvent(fcl, fe, op, postNotify);
1015
            }
1015
            }
1016
1016
1017
            if (onlyPriority) {
1017
            if (onlyPriority) {
Lines 1049-1062 Link Here
1049
                }
1049
                }
1050
                if (fs != null && fsList != null) {
1050
                if (fs != null && fsList != null) {
1051
                    for (FileChangeListener fcl : fsList) {
1051
                    for (FileChangeListener fcl : fsList) {
1052
                        FCLSupport.dispatchEvent(fcl, fe, op);
1052
                        FCLSupport.dispatchEvent(fcl, fe, op, postNotify);
1053
                    }  
1053
                    }  
1054
                }
1054
                }
1055
1055
1056
1056
1057
                if (rep != null && repList != null) {
1057
                if (rep != null && repList != null) {
1058
                    for (FileChangeListener fcl : repList) {
1058
                    for (FileChangeListener fcl : repList) {
1059
                        FCLSupport.dispatchEvent(fcl, fe, op);
1059
                        FCLSupport.dispatchEvent(fcl, fe, op, postNotify);
1060
                    }                      
1060
                    }                      
1061
                }
1061
                }
1062
            }
1062
            }
(-)a/openide.filesystems/src/org/openide/filesystems/FileSystem.java (-3 / +4 lines)
Lines 49-54 Link Here
49
import java.beans.VetoableChangeListener;
49
import java.beans.VetoableChangeListener;
50
import java.io.IOException;
50
import java.io.IOException;
51
import java.io.Serializable;
51
import java.io.Serializable;
52
import java.util.Collection;
52
import java.util.List;
53
import java.util.List;
53
import java.util.Set;
54
import java.util.Set;
54
import org.openide.util.Exceptions;
55
import org.openide.util.Exceptions;
Lines 877-889 Link Here
877
    */
878
    */
878
    static abstract class EventDispatcher extends Object implements Runnable {
879
    static abstract class EventDispatcher extends Object implements Runnable {
879
        public final void run() {
880
        public final void run() {
880
            dispatch(false);
881
            dispatch(false, null);
881
        }
882
        }
882
883
883
        /** @param onlyPriority if true then invokes only priority listeners
884
        /** @param onlyPriority if true then invokes only priority listeners
884
         *  else all listeners are invoked.
885
         *  else all listeners are invoked.
885
         */
886
         */
886
        protected abstract void dispatch(boolean onlyPriority);
887
        protected abstract void dispatch(boolean onlyPriority, Collection<Runnable> postNotify);
887
888
888
        /** @param propID  */
889
        /** @param propID  */
889
        protected abstract void setAtomicActionLink(EventControl.AtomicActionLink propID);
890
        protected abstract void setAtomicActionLink(EventControl.AtomicActionLink propID);
Lines 898-904 Link Here
898
            this.fStatusEvent = fStatusEvent;
899
            this.fStatusEvent = fStatusEvent;
899
        }
900
        }
900
901
901
        protected void dispatch(boolean onlyPriority) {
902
        protected void dispatch(boolean onlyPriority, Collection<Runnable> postNotify) {
902
            if (onlyPriority) {
903
            if (onlyPriority) {
903
                return;
904
                return;
904
            }
905
            }
(-)a/openide.filesystems/test/unit/src/org/openide/filesystems/AtomicActionTest.java (-1 / +13 lines)
Lines 94-99 Link Here
94
            }
94
            }
95
        });
95
        });
96
        assertTrue(tcl.deleteNotification);
96
        assertTrue(tcl.deleteNotification);
97
        assertTrue("Notified about end of delivery", tcl.over);
97
        tcl.reset();
98
        tcl.reset();
98
        assertNotNull(FileUtil.createData(root, "data"));        
99
        assertNotNull(FileUtil.createData(root, "data"));        
99
100
Lines 116-131 Link Here
116
            }
117
            }
117
        });
118
        });
118
        assertTrue(tcl.deleteNotification);
119
        assertTrue(tcl.deleteNotification);
120
        assertTrue("Notified about end of delivery", tcl.over);
119
    }
121
    }
120
    
122
    
121
    private static class TestChangeListener extends FileChangeAdapter {
123
    private static class TestChangeListener extends FileChangeAdapter
124
    implements Runnable {
122
        private boolean deleteNotification;
125
        private boolean deleteNotification;
126
        private boolean over;
123
        @Override
127
        @Override
124
        public void fileDeleted(FileEvent fe) {
128
        public void fileDeleted(FileEvent fe) {
129
            assertFalse("Delivery of events is not over yet", over);
125
            deleteNotification = true;
130
            deleteNotification = true;
131
            fe.runWhenDeliveryOver(this);
126
        }
132
        }
127
        public void reset() {
133
        public void reset() {
128
            deleteNotification = false;
134
            deleteNotification = false;
135
            over = false;
136
        }
137
138
        public void run() {
139
            assertFalse("Over not set yet", over);
140
            over = true;
129
        }
141
        }
130
    }    
142
    }    
131
}
143
}
(-)a/openide.filesystems/test/unit/src/org/openide/filesystems/FileObjectTestHid.java (-6 / +48 lines)
Lines 183-204 Link Here
183
                fail();
183
                fail();
184
            }
184
            }
185
        };
185
        };
186
        class Once implements Runnable {
187
            int once;
188
189
            public void run() {
190
                assertEquals("No calls yet", 0, once);
191
                once++;
192
            }
193
        }
194
        final Once post = new Once();
186
        final FileChangeListener listener1 = new FileChangeAdapter(){
195
        final FileChangeListener listener1 = new FileChangeAdapter(){
187
            @Override
196
            @Override
188
            public void fileDataCreated(FileEvent fe) {
197
            public void fileDataCreated(FileEvent fe) {
189
                fold.removeFileChangeListener(noFileDataCreatedListener);
198
                fold.removeFileChangeListener(noFileDataCreatedListener);
190
                fold.addFileChangeListener(noFileDataCreatedListener);
199
                fold.addFileChangeListener(noFileDataCreatedListener);
200
                fe.runWhenDeliveryOver(post);
191
            }
201
            }
192
        };
202
        };
193
        
203
        assertEquals("Not called yet", 0, post.once);
194
        try {
204
        try {
195
            fold.getFileSystem().addFileChangeListener(listener1);
205
            fold.getFileSystem().addFileChangeListener(listener1);
196
            fold.getFileSystem().runAtomicAction(new FileSystem.AtomicAction(){
206
            fold.getFileSystem().runAtomicAction(new FileSystem.AtomicAction(){
197
                public void run() throws java.io.IOException {
207
                public void run() throws java.io.IOException {
198
                    fold.createData("file1");
208
                    fold.createData("file1");
199
                    fold.createData("file2");
209
                    fold.createData("file2");
210
                    assertEquals("Called not", 0, post.once);
200
                }
211
                }
201
            });
212
            });
213
            assertEquals("Called once", 1, post.once);
202
        } finally {
214
        } finally {
203
            fold.getFileSystem().removeFileChangeListener(listener1);
215
            fold.getFileSystem().removeFileChangeListener(listener1);
204
            fold.removeFileChangeListener(noFileDataCreatedListener);
216
            fold.removeFileChangeListener(noFileDataCreatedListener);
Lines 989-1009 Link Here
989
    /** Test of fireFileRenamedEvent method, of class org.openide.filesystems.FileObject. */
1001
    /** Test of fireFileRenamedEvent method, of class org.openide.filesystems.FileObject. */
990
    public void  testFireFileRenamedEvent_FS() {
1002
    public void  testFireFileRenamedEvent_FS() {
991
        checkSetUp();
1003
        checkSetUp();
992
        FileObject fo = getTestFile1(root);
1004
        final FileObject fo = getTestFile1(root);
993
        registerDefaultListener(testedFS);
1005
        registerDefaultListener(testedFS);
994
        FileLock lock = null;
995
        
1006
        
1007
        class Immediate extends FileChangeAdapter implements Runnable {
1008
            int cnt;
1009
            FileRenameEvent fe;
1010
            @Override
1011
            public void fileRenamed(FileRenameEvent fe) {
1012
                int prev = cnt;
1013
                fe.runWhenDeliveryOver(this);
1014
                assertEquals("run() not called immediately", prev, cnt);
1015
                this.fe = fe;
1016
            }
1017
            public void run() {
1018
                cnt++;
1019
            }
1020
1021
            void testCallOutsideOfDeliverySystem() {
1022
                assertNotNull("There shall be an event", fe);
1023
                int prev = cnt;
1024
                fe.runWhenDeliveryOver(this);
1025
                assertEquals("run() called immediately", prev + 1, cnt);
1026
            }
1027
        }
1028
        Immediate immediately = new Immediate();
1029
        fo.addFileChangeListener(immediately);
1030
1031
        final FileLock[] lock = new FileLock[1];
996
        try {
1032
        try {
997
            lock = fo.lock();
1033
            lock[0] = fo.lock();
998
            fo.rename(lock,fo.getName()+"X",fo.getExt()+"X");
1034
            FileUtil.runAtomicAction(new FileSystem.AtomicAction() {
1035
                public void run() throws IOException {
1036
                    fo.rename(lock[0],fo.getName()+"X",fo.getExt()+"X");
1037
                }
1038
            });
999
        } catch (IOException iex) {
1039
        } catch (IOException iex) {
1000
            fsAssert("FileObject could not be renamed. So there was expected fs or fo are read-only",
1040
            fsAssert("FileObject could not be renamed. So there was expected fs or fo are read-only",
1001
            fs.isReadOnly() || root.isReadOnly());
1041
            fs.isReadOnly() || root.isReadOnly());
1002
            fileRenamedAssert("fs or fo is read-only. So no event should be fired",0);
1042
            fileRenamedAssert("fs or fo is read-only. So no event should be fired",0);
1003
            return;
1043
            return;
1004
        } finally {
1044
        } finally {
1005
            if (lock != null) lock.releaseLock();
1045
            if (lock[0] != null) lock[0].releaseLock();
1006
        }
1046
        }
1047
        assertEquals("One call", 1, immediately.cnt);
1048
        immediately.testCallOutsideOfDeliverySystem();
1007
        
1049
        
1008
        fileRenamedAssert("",1);        
1050
        fileRenamedAssert("",1);        
1009
        fileDataCreatedAssert("fireFileDataCreatedEvent should not be fired ",0);
1051
        fileDataCreatedAssert("fireFileDataCreatedEvent should not be fired ",0);

Return to bug 170544