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

(-)loaders/src/org/openide/loaders/DataObject.java (-6 / +19 lines)
Lines 503-509 Link Here
503
    public final DataObject copy (final DataFolder f) throws IOException {
503
    public final DataObject copy (final DataFolder f) throws IOException {
504
        final DataObject[] result = new DataObject[1];
504
        final DataObject[] result = new DataObject[1];
505
        FileSystem fs = f.getPrimaryFile ().getFileSystem ();
505
        FileSystem fs = f.getPrimaryFile ().getFileSystem ();
506
        fs.runAtomicAction (new FileSystem.AtomicAction () {
506
        invokeAtomicAction (fs, new FileSystem.AtomicAction () {
507
                                public void run () throws IOException {
507
                                public void run () throws IOException {
508
                                    result[0] = handleCopy (f);
508
                                    result[0] = handleCopy (f);
509
                                }
509
                                }
Lines 529-535 Link Here
529
        synchronized ( synchObject() ) {
529
        synchronized ( synchObject() ) {
530
            // the object is ready to be closed
530
            // the object is ready to be closed
531
            FileSystem fs = getPrimaryFile ().getFileSystem ();
531
            FileSystem fs = getPrimaryFile ().getFileSystem ();
532
            fs.runAtomicAction (new FileSystem.AtomicAction () {
532
            invokeAtomicAction (fs, new FileSystem.AtomicAction () {
533
                    public void run () throws IOException {
533
                    public void run () throws IOException {
534
                        handleDelete ();
534
                        handleDelete ();
535
                        item.deregister(false);
535
                        item.deregister(false);
Lines 574-580 Link Here
574
            
574
            
575
            // executes atomic action with renaming
575
            // executes atomic action with renaming
576
            FileSystem fs = files[0].getFileSystem ();
576
            FileSystem fs = files[0].getFileSystem ();
577
            fs.runAtomicAction (new FileSystem.AtomicAction () {
577
            invokeAtomicAction (fs, new FileSystem.AtomicAction () {
578
                    public void run () throws IOException {
578
                    public void run () throws IOException {
579
                        files[1] = handleRename (name);
579
                        files[1] = handleRename (name);
580
                        if (files[0] != files[1])
580
                        if (files[0] != files[1])
Lines 610-616 Link Here
610
            // executes atomic action for moving
610
            // executes atomic action for moving
611
            old = getPrimaryFile ();
611
            old = getPrimaryFile ();
612
            FileSystem fs = old.getFileSystem ();
612
            FileSystem fs = old.getFileSystem ();
613
            fs.runAtomicAction (new FileSystem.AtomicAction () {
613
            invokeAtomicAction (fs, new FileSystem.AtomicAction () {
614
                                    public void run () throws IOException {
614
                                    public void run () throws IOException {
615
                                        FileObject mf = handleMove (df);
615
                                        FileObject mf = handleMove (df);
616
                                        item.changePrimaryFile (mf);
616
                                        item.changePrimaryFile (mf);
Lines 654-660 Link Here
654
        final DataShadow[] result = new DataShadow[1];
654
        final DataShadow[] result = new DataShadow[1];
655
655
656
        FileSystem fs = f.getPrimaryFile ().getFileSystem ();
656
        FileSystem fs = f.getPrimaryFile ().getFileSystem ();
657
        fs.runAtomicAction (new FileSystem.AtomicAction () {
657
        invokeAtomicAction (fs, new FileSystem.AtomicAction () {
658
                                public void run () throws IOException {
658
                                public void run () throws IOException {
659
                                    result[0] =  handleCreateShadow (f);
659
                                    result[0] =  handleCreateShadow (f);
660
                                }
660
                                }
Lines 692-698 Link Here
692
        final DataObject[] result = new DataObject[1];
692
        final DataObject[] result = new DataObject[1];
693
693
694
        FileSystem fs = f.getPrimaryFile ().getFileSystem ();
694
        FileSystem fs = f.getPrimaryFile ().getFileSystem ();
695
        fs.runAtomicAction (new FileSystem.AtomicAction () {
695
        invokeAtomicAction (fs, new FileSystem.AtomicAction () {
696
                                public void run () throws IOException {
696
                                public void run () throws IOException {
697
                                    result[0] = handleCreateFromTemplate (f, name);
697
                                    result[0] = handleCreateFromTemplate (f, name);
698
                                }
698
                                }
Lines 736-741 Link Here
736
    Object synchObject() {
736
    Object synchObject() {
737
        return nodeCreationLock;
737
        return nodeCreationLock;
738
    }
738
    }
739
    
740
    /** Invokes atomic action. 
741
     */
742
    private void invokeAtomicAction (FileSystem fs, FileSystem.AtomicAction action) throws IOException {
743
        if (this instanceof DataFolder) {
744
            // action is slow
745
            fs.runAtomicAction(action);
746
        } else {
747
            // it is quick, make it block DataObject recognition
748
            DataObjectPool.getPOOL ().runAtomicAction (fs, action);
749
        }
750
    }
751
     
739
    
752
    
740
    //
753
    //
741
    // Property change support
754
    // Property change support
(-)loaders/src/org/openide/loaders/DataObjectPool.java (-1 / +84 lines)
Lines 79-84 Link Here
79
        
79
        
80
        Object prev = FIND.get ();
80
        Object prev = FIND.get ();
81
        try {
81
        try {
82
            // make sure this thread is allowed to recognize
83
            getPOOL ().enterRecognition();
84
            
82
            FIND.set (loader);
85
            FIND.set (loader);
83
            
86
            
84
            ret = loader.handleFindDataObject (fo, rec);
87
            ret = loader.handleFindDataObject (fo, rec);
Lines 142-147 Link Here
142
        return ret;
145
        return ret;
143
    }
146
    }
144
    
147
    
148
    
149
    //
150
    // Support for running really atomic actions
151
    //
152
    private Thread atomic;
153
    private RequestProcessor priviledged;
154
    public void runAtomicAction (FileSystem fs, FileSystem.AtomicAction action) 
155
    throws java.io.IOException {
156
        Thread prev;
157
        synchronized (this) {
158
            // make sure that we are the ones that own 
159
            // the recognition process
160
            enterRecognition ();
161
            prev = atomic;
162
            atomic = Thread.currentThread ();
163
        }
164
        
165
        try {
166
            fs.runAtomicAction(action);
167
        } finally {
168
            synchronized (this) {
169
                atomic = prev;
170
                notifyAll ();
171
            }
172
        }
173
    }
174
    
175
    /** The thread that runs in atomic action wants to delegate its priviledia
176
     * to somebody else. Used in DataFolder.getChildren that blocks on 
177
     * Folder Recognizer thread.
178
     *
179
     * @param delegate the priviledged processor
180
     */
181
    public synchronized void enterPriviledgedProcessor (RequestProcessor delegate) {
182
        if (atomic == Thread.currentThread()) {
183
            if (priviledged != null) throw new IllegalStateException ("Previous priviledged is not null: " + priviledged + " now: " + delegate); // NOI18N
184
            priviledged = delegate;
185
        }
186
    }
187
    
188
    /** Exits the priviledged processor.
189
     */
190
    public synchronized void exitPriviledgedProcessor (RequestProcessor delegate) {
191
        if (atomic == Thread.currentThread ()) {
192
            if (priviledged != delegate) throw new IllegalStateException ("Trying to unregister wrong priviledged. Prev: " + priviledged + " now: " + delegate); // NOI18N
193
            priviledged = null;
194
        }
195
    }
196
    
197
    /** Checks whether it is safe to enter the recognition. 
198
     */
199
    private synchronized void enterRecognition () {
200
        // wait till nobody else stops the recognition
201
        for (;;) {
202
            if (atomic == null) {
203
                // ok, I am the one who can enter
204
                return;
205
            }
206
            if (atomic == Thread.currentThread()) {
207
                // ok, reentering again
208
                return;
209
            }
210
            
211
            if (priviledged != null && priviledged.isRequestProcessorThread()) {
212
                // ok, we have priviledged request processor thread
213
                return;
214
            }
215
            
216
            try {
217
                wait ();
218
            } catch (InterruptedException ex) {
219
                // means nothing, go on
220
            }
221
        } 
222
    }
223
    
145
    /** Collection of all objects that has been created but their
224
    /** Collection of all objects that has been created but their
146
    * creation has not been yet notified to OperationListener.postCreate
225
    * creation has not been yet notified to OperationListener.postCreate
147
    * method.
226
    * method.
Lines 183-189 Link Here
183
    private DataObjectPool () {
262
    private DataObjectPool () {
184
    }
263
    }
185
264
186
265
    
187
266
188
    /** Checks whether there is a data object with primary file
267
    /** Checks whether there is a data object with primary file
189
    * passed thru the parameter.
268
    * passed thru the parameter.
Lines 193-198 Link Here
193
    */
272
    */
194
    public DataObject find (FileObject fo) {
273
    public DataObject find (FileObject fo) {
195
        synchronized (this) {
274
        synchronized (this) {
275
            enterRecognition();
276
            
196
            Item doh = (Item)map.get (fo);
277
            Item doh = (Item)map.get (fo);
197
            if (doh == null) {
278
            if (doh == null) {
198
                return null;
279
                return null;
Lines 313-318 Link Here
313
    public void waitNotified (DataObject obj) {
394
    public void waitNotified (DataObject obj) {
314
        try {
395
        try {
315
            synchronized (this) {
396
            synchronized (this) {
397
                enterRecognition ();
398
                
316
                if (toNotify.isEmpty()) {
399
                if (toNotify.isEmpty()) {
317
                    return;
400
                    return;
318
                }
401
                }
(-)loaders/src/org/openide/loaders/DataShadow.java (-1 / +1 lines)
Lines 231-237 Link Here
231
        final FileObject fo = folder.getPrimaryFile ();
231
        final FileObject fo = folder.getPrimaryFile ();
232
        final DataShadow[] arr = new DataShadow[1];
232
        final DataShadow[] arr = new DataShadow[1];
233
233
234
        fo.getFileSystem ().runAtomicAction (new FileSystem.AtomicAction () {
234
        DataObjectPool.getPOOL().runAtomicAction (fo.getFileSystem (), new FileSystem.AtomicAction () {
235
                                                 public void run () throws IOException {
235
                                                 public void run () throws IOException {
236
                                                     FileObject file = writeOriginal (name, ext, fo, original);
236
                                                     FileObject file = writeOriginal (name, ext, fo, original);
237
                                                     DataObject obj = DataObject.find (file);
237
                                                     DataObject obj = DataObject.find (file);
(-)loaders/src/org/openide/loaders/DataTransferSupport.java (-1 / +1 lines)
Lines 165-171 Link Here
165
            nd.setInputText (name);
165
            nd.setInputText (name);
166
166
167
            if (NotifyDescriptor.OK_OPTION == DialogDisplayer.getDefault ().notify (nd)) {
167
            if (NotifyDescriptor.OK_OPTION == DialogDisplayer.getDefault ().notify (nd)) {
168
                trg.getPrimaryFile ().getFileSystem ().runAtomicAction (new FileSystem.AtomicAction () {
168
                DataObjectPool.getPOOL().runAtomicAction (trg.getPrimaryFile ().getFileSystem (), new FileSystem.AtomicAction () {
169
                            public void run () throws IOException {
169
                            public void run () throws IOException {
170
                                FileObject fo = trg.getPrimaryFile ().createData (nd.getInputText (), "ser"); // NOI18N
170
                                FileObject fo = trg.getPrimaryFile ().createData (nd.getInputText (), "ser"); // NOI18N
171
                                FileLock lock = fo.lock ();
171
                                FileLock lock = fo.lock ();
(-)loaders/src/org/openide/loaders/FolderList.java (-2 / +8 lines)
Lines 217-224 Link Here
217
    * @return array with children
217
    * @return array with children
218
    */
218
    */
219
    public List getChildrenList () {
219
    public List getChildrenList () {
220
        ListTask lt = getChildrenList (null);
220
        ListTask lt;
221
        lt.task.waitFinished ();
221
        try {
222
            DataObjectPool.getPOOL().enterPriviledgedProcessor (PROCESSOR);
223
            lt = getChildrenList (null);
224
            lt.task.waitFinished();
225
        } finally {
226
            DataObjectPool.getPOOL().exitPriviledgedProcessor (PROCESSOR);
227
        }
222
        return lt.result;
228
        return lt.result;
223
    }
229
    }
224
230
(-)loaders/src/org/openide/loaders/InstanceDataObject.java (-2 / +2 lines)
Lines 219-225 Link Here
219
        if (newFile == null) {
219
        if (newFile == null) {
220
            final FileObject[] fos = new FileObject[1];
220
            final FileObject[] fos = new FileObject[1];
221
221
222
            fo.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() {
222
            DataObjectPool.getPOOL().runAtomicAction (fo.getFileSystem(), new FileSystem.AtomicAction() {
223
                public void run () throws IOException {
223
                public void run () throws IOException {
224
                    String fileName;
224
                    String fileName;
225
                    if (name == null) {
225
                    if (name == null) {
Lines 1375-1381 Link Here
1375
                me.name = name;
1375
                me.name = name;
1376
                me.create = create;
1376
                me.create = create;
1377
1377
1378
                folder.getPrimaryFile().getFileSystem().runAtomicAction(me);
1378
                DataObjectPool.getPOOL().runAtomicAction (folder.getPrimaryFile().getFileSystem(), me);
1379
                me.mi = null;
1379
                me.mi = null;
1380
                me.folder = null;
1380
                me.folder = null;
1381
                me.instance = null;
1381
                me.instance = null;
(-)test/unit/src/org/openide/loaders/SeparationOfThreadsTest.java (+310 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.loaders;
15
16
import org.openide.filesystems.*;
17
import org.openide.loaders.*;
18
import java.beans.*;
19
import java.io.IOException;
20
import junit.textui.TestRunner;
21
import org.netbeans.junit.*;
22
23
/* 
24
 * Checks whether a during a modify operation (copy, move) some
25
 * other thread can get a grip on unfinished and uncostructed 
26
 * content on filesystem.
27
 *
28
 * @author Jaroslav Tulach
29
 */
30
public class SeparationOfThreadsTest extends NbTestCase {
31
    private DataFolder root;
32
    private DataFolder to;
33
    private DataObject a;
34
    private DataObject b;
35
    private DataObject res;
36
37
    /** Creates the test */
38
    public SeparationOfThreadsTest(String name) {
39
        super(name);
40
    }
41
42
    // For each test setup a FileSystem and DataObjects
43
    protected void setUp() throws Exception {
44
        String fsstruct [] = new String [] {
45
            "A.attr", 
46
            "B.attr",
47
            "dir/",
48
            "fake/A.instance"
49
        };
50
        TestUtilHid.destroyLocalFileSystem (getName());
51
        FileSystem fs = TestUtilHid.createLocalFileSystem (getName(), fsstruct);
52
        root = DataFolder.findFolder (fs.getRoot ());
53
        
54
        AddLoaderManuallyHid.addRemoveLoader (ALoader.getLoader (ALoader.class), true);
55
        AddLoaderManuallyHid.addRemoveLoader (BLoader.getLoader (BLoader.class), true);
56
        
57
        to = DataFolder.findFolder (fs.findResource (fsstruct[2]));
58
        
59
        fs.findResource (fsstruct[0]).setAttribute ("A", Boolean.TRUE);
60
        
61
        a = DataObject.find (fs.findResource (fsstruct[0]));
62
        b = DataObject.find (fs.findResource (fsstruct[1]));
63
        
64
        ALoader loaderA = (ALoader)ALoader.getLoader (ALoader.class);
65
        
66
        assertEquals ("A is loaded by ALoader", loaderA, a.getLoader());
67
        assertEquals ("B is loaded by BLoader", ALoader.getLoader (BLoader.class), b.getLoader());
68
69
        // following code tests one bug that I have made during implementation
70
        // the runAtomicAction has to be run in finally block as some operation
71
        // can throw exceptions. This simulates operation that throws exception
72
        try {
73
            a.delete ();
74
            fail ("Should throw exception");
75
        } catch (IOException ex) {
76
            assertEquals ("Not implemented", ex.getMessage ());
77
        }
78
        
79
        synchronized (loaderA) {
80
            new Thread ((Runnable)loaderA).start ();
81
            loaderA.wait ();
82
        }
83
    }
84
    
85
    //Clear all stuff when the test finish
86
    protected void tearDown() throws Exception {
87
        ALoader loader = (ALoader)ALoader.getLoader(ALoader.class);
88
        synchronized (loader) {
89
            try {
90
                while (!loader.finished) {
91
                    loader.wait ();
92
                }
93
                
94
                assertNotNull (res);
95
                assertEquals ("The right loader synchronously", loader, res.getLoader ());
96
                
97
                if (loader.asyncError != null) {
98
                    throw loader.asyncError;
99
                }
100
                
101
                assertNotNull (loader.asyncRes);
102
                assertEquals ("It is the right loader asynchronously", loader, loader.asyncRes.getLoader());
103
                
104
            } finally {
105
                loader.asyncError = null;
106
                loader.currentThread = null;
107
                loader.current = null;
108
                loader.asyncRes = null;
109
                loader.finished = false;
110
                // clears any such flag
111
                Thread.interrupted();
112
113
114
                TestUtilHid.destroyLocalFileSystem (getName());
115
                AddLoaderManuallyHid.addRemoveLoader (ALoader.getLoader (ALoader.class), false);
116
                AddLoaderManuallyHid.addRemoveLoader (BLoader.getLoader (BLoader.class), false);
117
                
118
                // end of test
119
                loader.notify ();
120
            }            
121
        }
122
    }
123
    
124
    public static void main (String[] args) throws Exception {
125
         TestRunner.run(new NbTestSuite(SeparationOfThreadsTest.class));
126
    }    
127
128
    public void testCopy () throws Exception {
129
        res = a.copy (to);
130
    }
131
    
132
    public void testCreateFromTemplate () throws Exception {
133
        res = a.createFromTemplate (to);
134
    }
135
    public void testMove () throws Exception {
136
        a.move (to);
137
        res = a;
138
    }
139
    public void testRename () throws Exception {
140
        a.rename ("AnyThing");
141
        res = a;
142
    }
143
    
144
    //
145
    // Inner classes
146
    //
147
    
148
    public static final class ALoader extends UniFileLoader implements Runnable {
149
        DataObject asyncRes;
150
        Exception asyncError;
151
        FileObject current;
152
        Thread currentThread;
153
        boolean finished;
154
        
155
        public ALoader() {
156
            super(DataObject.class.getName());
157
        }
158
        protected void initialize() {
159
            super.initialize();
160
            getExtensions().addExtension("attr");
161
        }
162
        protected String displayName() {
163
            return getClass().getName ();
164
        }
165
        protected MultiDataObject createMultiObject(FileObject pf) throws IOException {
166
            return new MultiDataObject(pf, this);
167
        }
168
        
169
        protected org.openide.loaders.MultiDataObject.Entry createPrimaryEntry(org.openide.loaders.MultiDataObject multiDataObject, org.openide.filesystems.FileObject fileObject) {
170
            return new SlowEntry (multiDataObject, fileObject);
171
        }
172
        
173
        // 
174
        // Notification that the copy is in middle
175
        // 
176
        
177
        public void notifyCopied (FileObject current) {
178
            // first of all do some really ugly and complex operation
179
            try {
180
                DataObject[] arr = DataFolder.findFolder (current.getFileSystem ().findResource ("fake")).getChildren ();
181
                assertEquals ("In folder fake there is one object", 1, arr.length);
182
            } catch (FileStateInvalidException ex) {
183
                fail ("Wrong exception" + ex);
184
            }
185
            
186
            synchronized (this) {
187
                this.current = current;
188
                this.currentThread = Thread.currentThread ();
189
                this.notify ();
190
            }
191
            int cnt = 1;
192
            while (cnt-- > 0) {
193
                try {
194
                    Thread.sleep (500);
195
                } catch (InterruptedException ex) {
196
                    // is interrupted to be wake up sooner
197
                }
198
            }
199
        }
200
        
201
        //
202
        // The second thread that waits for the copy operation
203
        //
204
        public void run () {
205
            DataLoader loader = this;
206
            synchronized (loader) {
207
                // continue execution in setUp
208
                loader.notify ();
209
                // wait for being notify about copying
210
                try {
211
                    loader.wait ();
212
                } catch (InterruptedException ex) {
213
                    asyncError = ex;
214
                }
215
216
                try {
217
                    asyncRes = DataObject.find (current);
218
                    currentThread.interrupt();
219
                } catch (IOException ex) {
220
                    asyncError = ex;
221
                }
222
                
223
                // notify that we have computed everything
224
                finished = true;
225
                loader.notify ();
226
                
227
                while (asyncRes != null && asyncError != null) {
228
                    try {
229
                        loader.wait ();
230
                    } catch (InterruptedException ex) {
231
                    }
232
                }
233
            }
234
        }
235
        
236
    }
237
    
238
    public static final class BLoader extends UniFileLoader {
239
        public BLoader() {
240
            super(DataObject.class.getName());
241
        }
242
        protected void initialize() {
243
            super.initialize();
244
            getExtensions().addExtension("attr");
245
        }
246
        protected String displayName() {
247
            return getClass ().getName ();
248
        }
249
        protected org.openide.filesystems.FileObject findPrimaryFile(org.openide.filesystems.FileObject fileObject) {
250
            if (Boolean.TRUE.equals (fileObject.getAttribute ("A"))) {
251
                return null;
252
            }
253
            
254
            org.openide.filesystems.FileObject retValue;
255
            
256
            retValue = super.findPrimaryFile(fileObject);
257
            return retValue;
258
        }        
259
        
260
        protected MultiDataObject createMultiObject(FileObject pf) throws IOException {
261
            return new MultiDataObject(pf, this);
262
        }
263
    }
264
    
265
    private static final class SlowEntry extends MultiDataObject.Entry {
266
        public SlowEntry (MultiDataObject obj, FileObject fo) {
267
            obj.super (fo);
268
        }
269
        
270
        private void notifyCopied (FileObject fo) {
271
            ALoader l = (ALoader)ALoader.getLoader(ALoader.class);
272
            l.notifyCopied (fo);
273
        }
274
        
275
        public org.openide.filesystems.FileObject copy(org.openide.filesystems.FileObject fileObject, String str) throws java.io.IOException {
276
            FileObject ret = fileObject.createData ("copy", "attr");
277
            notifyCopied (ret);
278
            ret.setAttribute ("A", Boolean.TRUE);
279
            return ret;
280
        }
281
        
282
        public org.openide.filesystems.FileObject createFromTemplate(org.openide.filesystems.FileObject fileObject, String str) throws java.io.IOException {
283
            FileObject ret = fileObject.createData ("createFromTemplate", "attr");
284
            notifyCopied (ret);
285
            ret.setAttribute ("A", Boolean.TRUE);
286
            return ret;
287
        }
288
        
289
        public void delete() throws java.io.IOException {
290
            throw new IOException ("Not implemented");
291
        }
292
        
293
        public org.openide.filesystems.FileObject move(org.openide.filesystems.FileObject fileObject, String str) throws java.io.IOException {
294
            FileObject ret = fileObject.createData ("move", "attr");
295
            notifyCopied (ret);
296
            ret.setAttribute ("A", Boolean.TRUE);
297
            super.getFile ().delete ();
298
            return ret;
299
        }
300
        
301
        public org.openide.filesystems.FileObject rename(String str) throws java.io.IOException {
302
            FileObject ret = getFile ().getParent ().createData ("rename", "attr");
303
            notifyCopied (ret);
304
            ret.setAttribute ("A", Boolean.TRUE);
305
            super.getFile ().delete ();
306
            return ret;
307
        }
308
        
309
    }
310
}

Return to bug 33750