|
What this is
Other links
The source code
/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.loaders;
import org.openide.filesystems.*;
import org.openide.loaders.*;
import java.beans.*;
import java.io.IOException;
import junit.textui.TestRunner;
import org.netbeans.junit.*;
/*
* Checks whether a during a modify operation (copy, move) some
* other thread can get a grip on unfinished and uncostructed
* content on filesystem.
*
* @author Jaroslav Tulach
*/
public class SeparationOfThreadsTest extends NbTestCase {
private DataFolder root;
private DataFolder to;
private DataObject a;
private DataObject b;
private DataObject res;
/** Creates the test */
public SeparationOfThreadsTest(String name) {
super(name);
}
// For each test setup a FileSystem and DataObjects
protected void setUp() throws Exception {
String fsstruct [] = new String [] {
"source/A.attr",
"B.attr",
"dir/",
"fake/A.instance"
};
TestUtilHid.destroyLocalFileSystem (getName());
FileSystem fs = TestUtilHid.createLocalFileSystem (getName(), fsstruct);
root = DataFolder.findFolder (fs.getRoot ());
AddLoaderManuallyHid.addRemoveLoader (ALoader.getLoader (ALoader.class), true);
AddLoaderManuallyHid.addRemoveLoader (BLoader.getLoader (BLoader.class), true);
to = DataFolder.findFolder (fs.findResource (fsstruct[2]));
fs.findResource (fsstruct[0]).setAttribute ("A", Boolean.TRUE);
a = DataObject.find (fs.findResource (fsstruct[0]));
b = DataObject.find (fs.findResource (fsstruct[1]));
ALoader loaderA = (ALoader)ALoader.getLoader (ALoader.class);
assertEquals ("A is loaded by ALoader", loaderA, a.getLoader());
assertEquals ("B is loaded by BLoader", ALoader.getLoader (BLoader.class), b.getLoader());
// following code tests one bug that I have made during implementation
// the runAtomicAction has to be run in finally block as some operation
// can throw exceptions. This simulates operation that throws exception
try {
a.delete ();
fail ("Should throw exception");
} catch (IOException ex) {
assertEquals ("Not implemented", ex.getMessage ());
}
synchronized (loaderA) {
new Thread ((Runnable)loaderA, "Asynchronous access test").start ();
loaderA.wait ();
}
}
//Clear all stuff when the test finish
protected void tearDown() throws Exception {
ALoader loader = (ALoader)ALoader.getLoader(ALoader.class);
synchronized (loader) {
try {
while (!loader.finished) {
loader.wait ();
}
if (res == null) {
// an exception in testXXXX method
return;
}
assertEquals ("The right loader synchronously", loader, res.getLoader ());
if (loader.asyncError != null) {
throw loader.asyncError;
}
assertNotNull (loader.asyncRes);
assertEquals ("It is the right loader asynchronously", loader, loader.asyncRes.getLoader());
} finally {
loader.asyncError = null;
loader.currentThread = null;
loader.current = null;
loader.asyncRes = null;
loader.finished = false;
// clears any such flag
Thread.interrupted();
TestUtilHid.destroyLocalFileSystem (getName());
AddLoaderManuallyHid.addRemoveLoader (ALoader.getLoader (ALoader.class), false);
AddLoaderManuallyHid.addRemoveLoader (BLoader.getLoader (BLoader.class), false);
// end of test
loader.notify ();
}
}
}
public static void main (String[] args) throws Exception {
TestRunner.run(new NbTestSuite(SeparationOfThreadsTest.class));
}
public void testCopy () throws Exception {
res = a.copy (to);
}
public void testCreateFromTemplate () throws Exception {
res = a.createFromTemplate (to);
}
public void testMove () throws Exception {
a.move (to);
res = a;
}
public void testRename () throws Exception {
a.rename ("AnyThing");
res = a;
}
//
// Inner classes
//
public static final class ALoader extends UniFileLoader implements Runnable {
DataObject asyncRes;
Exception asyncError;
FileObject current;
Thread currentThread;
boolean finished;
public ALoader() {
super(DataObject.class.getName());
}
protected void initialize() {
super.initialize();
getExtensions().addExtension("attr");
}
protected String displayName() {
return getClass().getName ();
}
protected MultiDataObject createMultiObject(FileObject pf) throws IOException {
return new PostDataObject (pf, this);
}
protected org.openide.loaders.MultiDataObject.Entry createPrimaryEntry(org.openide.loaders.MultiDataObject multiDataObject, org.openide.filesystems.FileObject fileObject) {
return new SlowEntry (multiDataObject, fileObject);
}
//
// Notification that the copy is in middle
//
public void notifyCopied (final FileObject current) {
try {
if (current.getPath ().indexOf ("rename") < 0) {
// do not run this part for rename test
// first of all do some really ugly and complex operation =>
// get children of our target folder while we are modifying it
// ugly, but
DataObject[] arr = DataFolder.findFolder (current.getParent ()).getChildren ();
assertEquals ("In folder fake there is one object", 1, arr.length);
assertEquals ("The loader has to be the BLoader, as we are asking in the middle of copying",
DataLoader.findObject (BLoader.class),
arr[0].getLoader ()
);
java.lang.ref.WeakReference ref = new java.lang.ref.WeakReference (arr[0]);
arr = null;
assertGC ("The created object has to be garbage collected, otherwise the result of the test" +
" will not be the right DataObject, because the previous one already exists", ref
);
}
//
// Now something even uglier => any thread can call DataFolder.getChildren,
// but only on different folder than the one we are copying to
//
org.openide.util.RequestProcessor.getDefault().post (new Runnable () {
public void run () {
try {
final DataFolder queryOn = DataFolder.findFolder (current.getFileSystem().findResource("fake"));
DataObject[] one = queryOn.getChildren ();
assertEquals ("One object is in that folder", 1, one.length);
//
// Another uglyness => get access to already existing object outside of target folder
//
FileObject fo = current.getFileSystem().findResource("B.attr");
DataObject obj = DataObject.find (fo);
assertNotNull (obj);
java.lang.ref.WeakReference ref = new java.lang.ref.WeakReference (one[0]);
one = null;
assertGC ("The object has to disappear", ref);
} catch (java.io.IOException ex) {
fail ("should not happen");
}
}
}).waitFinished();
} finally {
synchronized (this) {
this.current = current;
this.currentThread = Thread.currentThread ();
this.notify ();
}
}
int cnt = 1;
while (cnt-- > 0) {
try {
Thread.sleep (500);
} catch (InterruptedException ex) {
// is interrupted to be wake up sooner
}
}
}
//
// The second thread that waits for the copy operation
//
public void run () {
DataLoader loader = this;
synchronized (loader) {
try {
// continue execution in setUp
loader.notify ();
// wait for being notify about copying
loader.wait ();
asyncRes = DataObject.find (current);
currentThread.interrupt();
} catch (InterruptedException ex) {
asyncError = ex;
} catch (IOException ex) {
asyncError = ex;
} finally {
// notify that we have computed everything
finished = true;
loader.notify ();
while (asyncRes != null && asyncError != null) {
try {
loader.wait ();
} catch (InterruptedException ex) {
}
}
}
}
}
} // end of ALoader
/** Calls super to do some copying and then does some post processing
*/
public static final class PostDataObject extends MultiDataObject {
public PostDataObject (FileObject fo, ALoader loader) throws DataObjectExistsException {
super (fo, loader);
}
/** Tryies to find a file in secondary thread.
*/
private void assertObject (final DataObject obj) {
final Object[] res = new Object[1];
org.openide.util.RequestProcessor.getDefault ().post (new Runnable () {
public void run () {
try {
res[0] = DataObject.find (obj.getPrimaryFile());
} catch (DataObjectNotFoundException ex) {
res[0] = ex;
}
}
}).waitFinished ();
assertEquals ("Objects are the same", obj, res[0]);
}
protected FileObject handleRename(String name) throws IOException {
FileObject retValue;
retValue = super.handleRename(name);
return retValue;
}
protected void handleDelete() throws IOException {
super.handleDelete();
}
protected DataObject handleCopy(DataFolder df) throws IOException {
DataObject retValue;
retValue = super.handleCopy(df);
assertObject (retValue);
return retValue;
}
protected DataObject handleCreateFromTemplate(DataFolder df, String name) throws IOException {
DataObject retValue;
retValue = super.handleCreateFromTemplate(df, name);
assertObject (retValue);
return retValue;
}
protected FileObject handleMove(DataFolder df) throws IOException {
FileObject retValue;
retValue = super.handleMove(df);
return retValue;
}
} // end of PostDataObject
public static final class BLoader extends UniFileLoader {
public BLoader() {
super(DataObject.class.getName());
}
protected void initialize() {
super.initialize();
getExtensions().addExtension("attr");
}
protected String displayName() {
return getClass ().getName ();
}
protected org.openide.filesystems.FileObject findPrimaryFile(org.openide.filesystems.FileObject fileObject) {
if (Boolean.TRUE.equals (fileObject.getAttribute ("A"))) {
return null;
}
org.openide.filesystems.FileObject retValue;
retValue = super.findPrimaryFile(fileObject);
return retValue;
}
protected MultiDataObject createMultiObject(FileObject pf) throws IOException {
return new MultiDataObject(pf, this);
}
}
private static final class SlowEntry extends MultiDataObject.Entry {
public SlowEntry (MultiDataObject obj, FileObject fo) {
obj.super (fo);
}
private void notifyCopied (FileObject fo) {
ALoader l = (ALoader)ALoader.getLoader(ALoader.class);
l.notifyCopied (fo);
}
public org.openide.filesystems.FileObject copy(org.openide.filesystems.FileObject fileObject, String str) throws java.io.IOException {
FileObject ret = fileObject.createData ("copy", "attr");
notifyCopied (ret);
ret.setAttribute ("A", Boolean.TRUE);
return ret;
}
public org.openide.filesystems.FileObject createFromTemplate(org.openide.filesystems.FileObject fileObject, String str) throws java.io.IOException {
FileObject ret = fileObject.createData ("createFromTemplate", "attr");
notifyCopied (ret);
ret.setAttribute ("A", Boolean.TRUE);
return ret;
}
public void delete() throws java.io.IOException {
throw new IOException ("Not implemented");
}
public org.openide.filesystems.FileObject move(org.openide.filesystems.FileObject fileObject, String str) throws java.io.IOException {
FileObject ret = fileObject.createData ("move", "attr");
notifyCopied (ret);
ret.setAttribute ("A", Boolean.TRUE);
super.getFile ().delete ();
return ret;
}
public org.openide.filesystems.FileObject rename(String str) throws java.io.IOException {
FileObject ret = getFile ().getParent ().createData ("rename", "attr");
super.getFile ().delete ();
notifyCopied (ret);
ret.setAttribute ("A", Boolean.TRUE);
return ret;
}
}
}
|
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.