| RE: [wtp-dev] JUnit tip: How to delete projects |
private
void
deleteFileAndUpdate(IFile file) throws Exception
{
ChangeListenerWithSemaphore listener = new
ChangeListenerWithSemaphore(1);
ResourcesPlugin.getWorkspace().addResourceChangeListener(listener,
IResourceChangeEvent.POST_CHANGE);
int retries =
3;
while (retries >
0) {
try {
deleteFile(file);
if
(listener.waitForEvents()) {
retries = 0;
break;
}
} catch
(CoreException e) {
... more core here... see in the description.
} finally {
retries--;
}
}
assertTrue(retries == -1);
ResourcesPlugin.getWorkspace().removeResourceChangeListener(listener);
}
The basic idea here is that you have not deleted a file/folder/project until you receive a ResourceChangeEvent for the deletion.
Since the event might be in the same thread or in another thread it is important to stop the current thread until an event occurs. This is what I am doing here. This has also worked for folders and projects. The listener.waitForEvents() is blocking the current thread until a notification for the deletion is received. In general the thread is blocked until the specified number of events (the number in the constructor of ChangeListenerWithSemaphore) is reached. But this can easily be changed to an another logic.
Here the "retires" are the number of failiers that I am willing to accept. In the catch(CoreException e) there is a special logic. If the message of the exception is "The requested operation cannot be performed on a file with a user-mapped section open" the code of the catch block is:
/*
* An exception was occurring
- "The requested operation cannot
* be performed on a file
with a user-mapped section open".
* Running the finalization
as suggested at
*
http://webteam.archive.org/jira/browse/HER-661?decorator=printable
*/
System.runFinalization();
System.gc();
But I was unable to investigate the error more deeply.The deleteFile method is:
protected
static
boolean
deleteFile(final IFile file)
throws Exception
{
ResourcesPlugin.getWorkspace().run(new
IWorkspaceRunnable() {
public
void
run(IProgressMonitor monitor) throws CoreException
{
file.delete(false,
monitor);
}
}, monitor);
return true;
}
The code of ChangeListenerWithSemaphore is
/**
* This change listener will release a semaphore after the resource changed
* method is called. For every resourceChanged call one release will be called.
*
*
@author
Kiril
Mitov
k.mitov@xxxxxxx
*
*/
public
final
class
ChangeListenerWithSemaphore implements
IResourceChangeListener {
private
final Semaphore
s;
private
final
List<Object> deltas;
private
final
int expectedEvents;
private
final
List<IResourceChangeEvent> receivedEvents;
public
ChangeListenerWithSemaphore(int
expectedEvents) throws
InterruptedException {
this.expectedEvents =
expectedEvents;
this.s =
new
Semaphore(1);
this.s.acquire();
this.deltas =
Collections.synchronizedList(new
LinkedList<Object>());
this.receivedEvents =
Collections.synchronizedList(new
LinkedList<IResourceChangeEvent>());
}
public
synchronized
void
resourceChanged(IResourceChangeEvent event) {
receivedEvents.add(event);
if (receivedEvents.size() >
expectedEvents)
throw
new
IllegalStateException("The
expected events were already reached");
try {
deltas.add(event.getDelta());
} catch (Exception e)
{
Activator.getDefault().getLog().log(new
Status(IStatus.ERROR,
Activator.PLUGIN_ID,
e.getMessage(), e));
return;
} finally {
if (expectedEvents ==
receivedEvents.size())
s.release();
}
}
public
boolean
waitForEvents() throws
InterruptedException {
return s.tryAcquire(5,
TimeUnit.SECONDS);
}
public
synchronized
List<Object> getDeltas() {
return deltas;
}
public
synchronized
int getEvents()
{
return receivedEvents.size();
}
public
List<IResourceChangeEvent> getReceivedEvents() {
return receivedEvents;
}
}
This is how I am creating, deleting and updating files.
Best Regards,
Kiril