KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > loaders > SeparationOfThreadsTest


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.loaders;
21
22 import org.openide.filesystems.*;
23 import org.openide.loaders.*;
24 import java.beans.*;
25 import java.io.IOException JavaDoc;
26 import junit.textui.TestRunner;
27 import org.netbeans.junit.*;
28
29 /*
30  * Checks whether a during a modify operation (copy, move) some
31  * other thread can get a grip on unfinished and uncostructed
32  * content on filesystem.
33  *
34  * @author Jaroslav Tulach
35  */

36 public class SeparationOfThreadsTest extends NbTestCase {
37     private DataFolder root;
38     private DataFolder to;
39     private DataObject a;
40     private DataObject b;
41     private DataObject res;
42
43     /** Creates the test */
44     public SeparationOfThreadsTest(String JavaDoc name) {
45         super(name);
46     }
47
48     // For each test setup a FileSystem and DataObjects
49
protected void setUp() throws Exception JavaDoc {
50         clearWorkDir();
51         String JavaDoc fsstruct [] = new String JavaDoc [] {
52             "source/A.attr",
53             "B.attr",
54             "dir/",
55             "fake/A.instance"
56         };
57         TestUtilHid.destroyLocalFileSystem (getName());
58         FileSystem fs = TestUtilHid.createLocalFileSystem (getWorkDir(), fsstruct);
59         root = DataFolder.findFolder (fs.getRoot ());
60         
61         AddLoaderManuallyHid.addRemoveLoader (ALoader.getLoader (ALoader.class), true);
62         AddLoaderManuallyHid.addRemoveLoader (BLoader.getLoader (BLoader.class), true);
63         
64         to = DataFolder.findFolder (fs.findResource (fsstruct[2]));
65         
66         fs.findResource (fsstruct[0]).setAttribute ("A", Boolean.TRUE);
67         
68         a = DataObject.find (fs.findResource (fsstruct[0]));
69         b = DataObject.find (fs.findResource (fsstruct[1]));
70         
71         ALoader loaderA = (ALoader)ALoader.getLoader (ALoader.class);
72         
73         assertEquals ("A is loaded by ALoader", loaderA, a.getLoader());
74         assertEquals ("B is loaded by BLoader", ALoader.getLoader (BLoader.class), b.getLoader());
75
76         // following code tests one bug that I have made during implementation
77
// the runAtomicAction has to be run in finally block as some operation
78
// can throw exceptions. This simulates operation that throws exception
79
try {
80             a.delete ();
81             fail ("Should throw exception");
82         } catch (IOException JavaDoc ex) {
83             assertEquals ("Not implemented", ex.getMessage ());
84         }
85         
86         synchronized (loaderA) {
87             new Thread JavaDoc ((Runnable JavaDoc)loaderA, "Asynchronous access test").start ();
88             loaderA.wait ();
89         }
90     }
91     
92     //Clear all stuff when the test finish
93
protected void tearDown() throws Exception JavaDoc {
94         ALoader loader = (ALoader)ALoader.getLoader(ALoader.class);
95         synchronized (loader) {
96             try {
97                 int cnt = 0;
98                 while (!loader.finished) {
99                     loader.wait(1000);
100                     assertTrue("apparent hang in tearDown", cnt++ < 100);
101                 }
102
103                 if (res == null) {
104                     // an exception in testXXXX method
105
return;
106                 }
107                 
108                 assertEquals ("The right loader synchronously", loader, res.getLoader ());
109                 
110                 if (loader.asyncError != null) {
111                     throw loader.asyncError;
112                 }
113                 
114                 assertNotNull (loader.asyncRes);
115                 assertEquals ("It is the right loader asynchronously", loader, loader.asyncRes.getLoader());
116                 
117             } finally {
118                 loader.asyncError = null;
119                 loader.currentThread = null;
120                 loader.current = null;
121                 loader.asyncRes = null;
122                 loader.finished = false;
123                 // clears any such flag
124
Thread.interrupted();
125
126
127                 TestUtilHid.destroyLocalFileSystem (getName());
128                 AddLoaderManuallyHid.addRemoveLoader (ALoader.getLoader (ALoader.class), false);
129                 AddLoaderManuallyHid.addRemoveLoader (BLoader.getLoader (BLoader.class), false);
130                 
131                 // end of test
132
loader.notify ();
133             }
134         }
135     }
136
137     public void testCopy () throws Exception JavaDoc {
138         res = a.copy (to);
139     }
140     
141     public void testCreateFromTemplate () throws Exception JavaDoc {
142         res = a.createFromTemplate (to);
143     }
144     public void testMove () throws Exception JavaDoc {
145         a.move (to);
146         res = a;
147     }
148     
149     public void testRename () throws Exception JavaDoc {
150         a.rename ("AnyThing");
151         res = a;
152     }
153     
154     //
155
// Inner classes
156
//
157

158     public static final class ALoader extends UniFileLoader implements Runnable JavaDoc {
159         DataObject asyncRes;
160         Exception JavaDoc asyncError;
161         FileObject current;
162         Thread JavaDoc currentThread;
163         boolean finished;
164         
165         public ALoader() {
166             super(DataObject.class.getName());
167         }
168         protected void initialize() {
169             super.initialize();
170             getExtensions().addExtension("attr");
171         }
172         protected String JavaDoc displayName() {
173             return getClass().getName ();
174         }
175         protected MultiDataObject createMultiObject(FileObject pf) throws IOException JavaDoc {
176             return new PostDataObject (pf, this);
177         }
178         
179         protected org.openide.loaders.MultiDataObject.Entry createPrimaryEntry(org.openide.loaders.MultiDataObject multiDataObject, org.openide.filesystems.FileObject fileObject) {
180             return new SlowEntry (multiDataObject, fileObject);
181         }
182         
183         //
184
// Notification that the copy is in middle
185
//
186

187         public void notifyCopied (final FileObject current) {
188             try {
189                 if (current.getPath ().indexOf ("rename") < 0) {
190                     // do not run this part for rename test
191

192                     // first of all do some really ugly and complex operation =>
193
// get children of our target folder while we are modifying it
194
// ugly, but
195
DataObject[] arr = DataFolder.findFolder (current.getParent ()).getChildren ();
196                     assertEquals ("In folder fake there is one object", 1, arr.length);
197                     assertEquals ("The loader has to be the BLoader, as we are asking in the middle of copying",
198                         DataLoader.findObject (BLoader.class),
199                         arr[0].getLoader ()
200                     );
201
202                     java.lang.ref.WeakReference JavaDoc ref = new java.lang.ref.WeakReference JavaDoc (arr[0]);
203                     arr = null;
204                     assertGC ("The created object has to be garbage collected, otherwise the result of the test" +
205                         " will not be the right DataObject, because the previous one already exists", ref
206                     );
207                 }
208                     
209                 //
210
// Now something even uglier => any thread can call DataFolder.getChildren,
211
// but only on different folder than the one we are copying to
212
//
213
org.openide.util.RequestProcessor.getDefault().post (new Runnable JavaDoc () {
214                     public void run () {
215                         try {
216                             final DataFolder queryOn = DataFolder.findFolder (current.getFileSystem().findResource("fake"));
217                             DataObject[] one = queryOn.getChildren ();
218                             assertEquals ("One object is in that folder", 1, one.length);
219
220                             //
221
// Another uglyness => get access to already existing object outside of target folder
222
//
223
FileObject fo = current.getFileSystem().findResource("B.attr");
224                             DataObject obj = DataObject.find (fo);
225                             assertNotNull (obj);
226                             
227                             java.lang.ref.WeakReference JavaDoc ref = new java.lang.ref.WeakReference JavaDoc (one[0]);
228                             one = null;
229                             assertGC ("The object has to disappear", ref);
230
231                         } catch (java.io.IOException JavaDoc ex) {
232                             fail ("should not happen");
233                         }
234                     }
235                 }).waitFinished();
236
237
238             } finally {
239                 synchronized (this) {
240                     this.current = current;
241                     this.currentThread = Thread.currentThread ();
242                     this.notify ();
243                 }
244             }
245             
246             int cnt = 1;
247             while (cnt-- > 0) {
248                 try {
249                     Thread.sleep (500);
250                 } catch (InterruptedException JavaDoc ex) {
251                     // is interrupted to be wake up sooner
252
}
253             }
254         }
255         
256         //
257
// The second thread that waits for the copy operation
258
//
259
public void run () {
260             DataLoader loader = this;
261             synchronized (loader) {
262
263                 try {
264                     // continue execution in setUp
265
loader.notify ();
266                     
267                     // wait for being notify about copying
268
loader.wait ();
269                     
270                     asyncRes = DataObject.find (current);
271                     currentThread.interrupt();
272                 } catch (InterruptedException JavaDoc ex) {
273                     asyncError = ex;
274                 } catch (IOException JavaDoc ex) {
275                     asyncError = ex;
276                 } finally {
277                     // notify that we have computed everything
278
finished = true;
279                     loader.notify ();
280
281                     while (asyncRes != null && asyncError != null) {
282                         try {
283                             loader.wait ();
284                         } catch (InterruptedException JavaDoc ex) {
285                         }
286                     }
287                 }
288             }
289         }
290         
291     } // end of ALoader
292

293     /** Calls super to do some copying and then does some post processing
294      */

295     public static final class PostDataObject extends MultiDataObject {
296        public PostDataObject (FileObject fo, ALoader loader) throws DataObjectExistsException {
297            super (fo, loader);
298        }
299
300        /** Tryies to find a file in secondary thread.
301         */

302        private void assertObject (final DataObject obj) {
303            final Object JavaDoc[] res = new Object JavaDoc[1];
304            org.openide.util.RequestProcessor.getDefault ().post (new Runnable JavaDoc () {
305                 public void run () {
306                     try {
307                         res[0] = DataObject.find (obj.getPrimaryFile());
308                     } catch (DataObjectNotFoundException ex) {
309                         res[0] = ex;
310                     }
311                 }
312            }).waitFinished ();
313            
314            assertEquals ("Objects are the same", obj, res[0]);
315        }
316            
317        
318        protected FileObject handleRename(String JavaDoc name) throws IOException JavaDoc {
319            FileObject retValue;
320            retValue = super.handleRename(name);
321            return retValue;
322        }
323        
324        protected void handleDelete() throws IOException JavaDoc {
325            super.handleDelete();
326        }
327         
328        protected DataObject handleCopy(DataFolder df) throws IOException JavaDoc {
329            DataObject retValue;
330            
331            retValue = super.handleCopy(df);
332            
333            assertObject (retValue);
334            return retValue;
335        }
336        
337        protected DataObject handleCreateFromTemplate(DataFolder df, String JavaDoc name) throws IOException JavaDoc {
338            DataObject retValue;
339            
340            retValue = super.handleCreateFromTemplate(df, name);
341            
342            assertObject (retValue);
343            return retValue;
344        }
345        
346        protected FileObject handleMove(DataFolder df) throws IOException JavaDoc {
347            FileObject retValue;
348            
349            retValue = super.handleMove(df);
350            return retValue;
351        }
352        
353     } // end of PostDataObject
354

355     public static final class BLoader extends UniFileLoader {
356         public BLoader() {
357             super(DataObject.class.getName());
358         }
359         protected void initialize() {
360             super.initialize();
361             getExtensions().addExtension("attr");
362         }
363         protected String JavaDoc displayName() {
364             return getClass ().getName ();
365         }
366         protected org.openide.filesystems.FileObject findPrimaryFile(org.openide.filesystems.FileObject fileObject) {
367             if (Boolean.TRUE.equals (fileObject.getAttribute ("A"))) {
368                 return null;
369             }
370             
371             org.openide.filesystems.FileObject retValue;
372             
373             retValue = super.findPrimaryFile(fileObject);
374             return retValue;
375         }
376         
377         protected MultiDataObject createMultiObject(FileObject pf) throws IOException JavaDoc {
378             return new MultiDataObject(pf, this);
379         }
380     }
381     
382     private static final class SlowEntry extends MultiDataObject.Entry {
383         public SlowEntry (MultiDataObject obj, FileObject fo) {
384             obj.super (fo);
385         }
386         
387         private void notifyCopied (FileObject fo) {
388             ALoader l = (ALoader)ALoader.getLoader(ALoader.class);
389             l.notifyCopied (fo);
390         }
391         
392         public org.openide.filesystems.FileObject copy(org.openide.filesystems.FileObject fileObject, String JavaDoc str) throws java.io.IOException JavaDoc {
393             FileObject ret = fileObject.createData ("copy", "attr");
394             notifyCopied (ret);
395             ret.setAttribute ("A", Boolean.TRUE);
396             return ret;
397         }
398         
399         public org.openide.filesystems.FileObject createFromTemplate(org.openide.filesystems.FileObject fileObject, String JavaDoc str) throws java.io.IOException JavaDoc {
400             FileObject ret = fileObject.createData ("createFromTemplate", "attr");
401             notifyCopied (ret);
402             ret.setAttribute ("A", Boolean.TRUE);
403             return ret;
404         }
405         
406         public void delete() throws java.io.IOException JavaDoc {
407             throw new IOException JavaDoc ("Not implemented");
408         }
409         
410         public org.openide.filesystems.FileObject move(org.openide.filesystems.FileObject fileObject, String JavaDoc str) throws java.io.IOException JavaDoc {
411             FileObject ret = fileObject.createData ("move", "attr");
412             notifyCopied (ret);
413             ret.setAttribute ("A", Boolean.TRUE);
414             super.getFile ().delete ();
415             return ret;
416         }
417         
418         public org.openide.filesystems.FileObject rename(String JavaDoc str) throws java.io.IOException JavaDoc {
419             FileObject ret = getFile ().getParent ().createData ("rename", "attr");
420             super.getFile ().delete ();
421             notifyCopied (ret);
422             ret.setAttribute ("A", Boolean.TRUE);
423             return ret;
424         }
425         
426     }
427 }
428
Popular Tags