diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/FileOperations.java b/common/source/java/ch/systemsx/cisd/common/filesystem/FileOperations.java
index 0242ce5e5cc0f7305f3b0da5eee76ac05ec8374d..b709dcf7354c5187d810e8b25a0297e293798c69 100644
--- a/common/source/java/ch/systemsx/cisd/common/filesystem/FileOperations.java
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/FileOperations.java
@@ -20,16 +20,20 @@ import java.io.File;
 import java.io.FileFilter;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.List;
 
 import org.apache.commons.io.FileCopyUtils;
+import org.apache.commons.io.FileSystemUtils;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.log4j.Logger;
 
+import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.common.TimingParameters;
 import ch.systemsx.cisd.common.concurrent.IActivityObserver;
 import ch.systemsx.cisd.common.concurrent.MonitoringProxy;
@@ -49,7 +53,7 @@ import ch.systemsx.cisd.common.utilities.FileUtilities;
 public class FileOperations implements IFileOperations
 {
 
-    // @Private
+    @Private
     final static Logger operationLog =
             LogFactory.getLogger(LogCategory.OPERATION, IFileOperations.class);
 
@@ -129,7 +133,7 @@ public class FileOperations implements IFileOperations
 
     private final IActivityObserver observerOrNull;
 
-    // @Private
+    @Private
     FileOperations(TimingParameters timingParametersOrNull, IActivityObserver observerOrNull)
     {
         this.timingParametersOrNull = timingParametersOrNull;
@@ -367,6 +371,11 @@ public class FileOperations implements IFileOperations
         return FileUtilities.deleteRecursively(fileToRemove, null, observerOrNull);
     }
 
+    public boolean removeRecursivelyQueueing(File fileToRemove)
+    {
+        return QueueingPathRemoverService.removeRecursively(fileToRemove);
+    }
+
     public void move(File source, File destination) throws WrappedIOException
     {
         if (destination.isDirectory())
@@ -518,15 +527,57 @@ public class FileOperations implements IFileOperations
         }
     }
 
-    // @Private
+    @Private
     IInputStream internalGetIInputStream(File file) throws FileNotFoundException
     {
         return new InputStreamAdapter(new FileInputStream(file));
     }
 
+    public OutputStream getOutputStream(File file) throws WrappedIOException
+    {
+        return new IOutputStreamAdapter(getIOutputStream(file));
+    }
+
+    public IOutputStream getIOutputStream(File file) throws WrappedIOException
+    {
+        try
+        {
+            final IOutputStream os = internalGetIOutputStream(file);
+            if (timingParametersOrNull != null)
+            {
+                return MonitoringProxy.create(IOutputStream.class, os).timing(
+                        timingParametersOrNull).name(
+                        "output stream <" + file.getAbsolutePath() + ">").get();
+            } else
+            {
+                return os;
+            }
+        } catch (IOException ex)
+        {
+            throw new WrappedIOException(ex);
+        }
+    }
+
+    @Private
+    IOutputStream internalGetIOutputStream(File file) throws FileNotFoundException
+    {
+        return new OutputStreamAdapter(new FileOutputStream(file));
+    }
+
     public void writeToFile(File file, String content) throws WrappedIOException
     {
         FileUtilities.writeToFile(file, content);
     }
 
+    public long freeSpaceKb(String path) throws WrappedIOException
+    {
+        try
+        {
+            return FileSystemUtils.freeSpaceKb(path);
+        } catch (IOException ex)
+        {
+            throw new WrappedIOException(ex);
+        }
+    }
+
 }
diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/IFileOperations.java b/common/source/java/ch/systemsx/cisd/common/filesystem/IFileOperations.java
index 458d304bf5dd0307ed140a8d9e9cb907a76879f1..7e9f7c59cccbdeec279fa4bbb66c31d1558f75bf 100644
--- a/common/source/java/ch/systemsx/cisd/common/filesystem/IFileOperations.java
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/IFileOperations.java
@@ -20,8 +20,11 @@ import java.io.File;
 import java.io.FileFilter;
 import java.io.FilenameFilter;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.List;
 
+import org.apache.commons.io.FileSystemUtils;
+
 import ch.systemsx.cisd.common.exceptions.WrappedIOException;
 
 /**
@@ -262,6 +265,17 @@ public interface IFileOperations extends IFileRemover
      */
     public void deleteRecursively(File fileToRemove) throws WrappedIOException;
 
+    /**
+     * Removes the given <var>fileToRemove</var>, if necessary recursively. If it is a file, it will
+     * be deleted immediately, if it is a directory, it will be queued up for asynchronous deletion.
+     * 
+     * @param fileToRemove File or directory to remove. If it is a directory, it will be removed
+     *            asynchronous recursively.
+     * @return <code>true</code> if the file or directory was removed successfully and
+     *         <code>false</code> otherwise.
+     */
+    public boolean removeRecursivelyQueueing(File fileToRemove);
+
     /**
      * Move <var>source</var> to <var>destinationDirectory</var>.
      * 
@@ -431,6 +445,20 @@ public interface IFileOperations extends IFileRemover
      */
     public IInputStream getIInputStream(File file) throws WrappedIOException;
 
+    /**
+     * Returns a monitored {@link InputStream} of <var>file</var>.
+     * 
+     * @throws WrappedIOException if an IO error occurs during opening the stream
+     */
+    public OutputStream getOutputStream(File file) throws WrappedIOException;
+
+    /**
+     * Returns a monitored {@link IInputStream} of <var>file</var>.
+     * 
+     * @throws WrappedIOException if an IO error occurs during opening the stream
+     */
+    public IOutputStream getIOutputStream(File file) throws WrappedIOException;
+
     /**
      * Writes <var>content</var> to <var>file</var>. If <var>file</var> already exists, it will be
      * overwritten.
@@ -438,4 +466,14 @@ public interface IFileOperations extends IFileRemover
      * @throws WrappedIOException if an IO error occurs during writing
      */
     public void writeToFile(File file, String content) throws WrappedIOException;
+
+    //
+    // File system
+    //
+
+    /**
+     * @see FileSystemUtils#freeSpaceKb(String)
+     */
+    public long freeSpaceKb(String path) throws WrappedIOException;
+
 }
diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/IInputStream.java b/common/source/java/ch/systemsx/cisd/common/filesystem/IInputStream.java
index d1985d6601330a2a895c0bdc78df3ead22b07425..e140a6a8b5995ebecaa387bfb72d735cca16cc39 100644
--- a/common/source/java/ch/systemsx/cisd/common/filesystem/IInputStream.java
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/IInputStream.java
@@ -19,7 +19,7 @@ package ch.systemsx.cisd.common.filesystem;
 import ch.systemsx.cisd.common.exceptions.WrappedIOException;
 
 /**
- * In interface for {@link java.io.InputStream}.
+ * An interface for {@link java.io.InputStream}.
  *
  * @author Bernd Rinn
  */
diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/IInputStreamAdapter.java b/common/source/java/ch/systemsx/cisd/common/filesystem/IInputStreamAdapter.java
index d4cab963c7bdffd50ca1d8eaf62255236782e3c3..5640dfae4ebdd0642da2af2842fce01075e22a77 100644
--- a/common/source/java/ch/systemsx/cisd/common/filesystem/IInputStreamAdapter.java
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/IInputStreamAdapter.java
@@ -44,7 +44,7 @@ public class IInputStreamAdapter extends InputStream
             return delegate.available();
         } catch (WrappedIOException ex)
         {
-            throw (IOException) ex.getCause();
+            throw ex.getCause();
         }
     }
 
@@ -56,7 +56,7 @@ public class IInputStreamAdapter extends InputStream
             delegate.close();
         } catch (WrappedIOException ex)
         {
-            throw (IOException) ex.getCause();
+            throw ex.getCause();
         }
     }
 
@@ -80,7 +80,7 @@ public class IInputStreamAdapter extends InputStream
             return delegate.read();
         } catch (WrappedIOException ex)
         {
-            throw (IOException) ex.getCause();
+            throw ex.getCause();
         }
     }
 
@@ -92,7 +92,7 @@ public class IInputStreamAdapter extends InputStream
             return delegate.read(b, off, len);
         } catch (WrappedIOException ex)
         {
-            throw (IOException) ex.getCause();
+            throw ex.getCause();
         }
     }
 
@@ -104,7 +104,7 @@ public class IInputStreamAdapter extends InputStream
             return delegate.read(b);
         } catch (WrappedIOException ex)
         {
-            throw (IOException) ex.getCause();
+            throw ex.getCause();
         }
     }
 
@@ -116,7 +116,7 @@ public class IInputStreamAdapter extends InputStream
             delegate.reset();
         } catch (WrappedIOException ex)
         {
-            throw (IOException) ex.getCause();
+            throw ex.getCause();
         }
     }
 
@@ -128,8 +128,30 @@ public class IInputStreamAdapter extends InputStream
             return delegate.skip(n);
         } catch (WrappedIOException ex)
         {
-            throw (IOException) ex.getCause();
+            throw ex.getCause();
         }
     }
 
+    //
+    // Object
+    //
+    
+    @Override
+    public boolean equals(Object obj)
+    {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return delegate.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return delegate.toString();
+    }
+
 }
diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/IOutputStream.java b/common/source/java/ch/systemsx/cisd/common/filesystem/IOutputStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d6956dafba69b4cf2c124fc27e4eda96e619bb9
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/IOutputStream.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.filesystem;
+
+import ch.systemsx.cisd.common.exceptions.WrappedIOException;
+
+/**
+ * An interface for {@link java.io.OutputStream}.
+ * 
+ * @author Bernd Rinn
+ */
+public interface IOutputStream extends ICloseable, ISynchronizable
+{
+    /**
+     * @see java.io.OutputStream#write(int)
+     */
+    public void write(int b) throws WrappedIOException;
+
+    /**
+     * @see java.io.OutputStream#write(byte[])
+     */
+    public void write(byte b[]) throws WrappedIOException;
+
+    /**
+     * @see java.io.OutputStream#write(byte[], int, int)
+     */
+    public void write(byte b[], int off, int len) throws WrappedIOException;
+
+    /**
+     * @see java.io.OutputStream#flush()
+     */
+    public void flush() throws WrappedIOException;
+
+    /**
+     * @see java.io.OutputStream#flush()
+     */
+    public void synchronize() throws WrappedIOException;
+
+    /**
+     * @see java.io.OutputStream#close()
+     */
+    public void close() throws WrappedIOException;
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/IOutputStreamAdapter.java b/common/source/java/ch/systemsx/cisd/common/filesystem/IOutputStreamAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..8343d364a84dc2991376777e3026a7aadf0637d4
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/IOutputStreamAdapter.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.filesystem;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import ch.systemsx.cisd.common.exceptions.WrappedIOException;
+
+/**
+ * An adapter for {@link IOutputStream} that extends {@link java.io.OutputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class IOutputStreamAdapter extends OutputStream
+{
+
+    private final IOutputStream delegate;
+    
+    public IOutputStreamAdapter(IOutputStream delegate)
+    {
+        this.delegate = delegate;
+    }
+    
+    @Override
+    public void write(int b) throws IOException
+    {
+        try
+        {
+            delegate.write(b);
+        } catch (WrappedIOException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public void close() throws IOException
+    {
+        try
+        {
+            delegate.close();
+        } catch (WrappedIOException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public void flush() throws IOException
+    {
+        try
+        {
+            delegate.flush();
+        } catch (WrappedIOException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException
+    {
+        try
+        {
+            delegate.write(b, off, len);
+        } catch (WrappedIOException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public void write(byte[] b) throws IOException
+    {
+        try
+        {
+            delegate.write(b);
+        } catch (WrappedIOException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public boolean equals(Object obj)
+    {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return delegate.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return delegate.toString();
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/OutputStreamAdapter.java b/common/source/java/ch/systemsx/cisd/common/filesystem/OutputStreamAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..347e0fd4fcf593e304ddea5d1a80639a09692014
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/OutputStreamAdapter.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.filesystem;
+
+import java.io.IOException;
+
+import ch.systemsx.cisd.common.exceptions.WrappedIOException;
+
+/**
+ * An adapter for {@link java.io.OutputStream} that implements {@link IOutputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class OutputStreamAdapter implements IOutputStream
+{
+    
+    private final java.io.OutputStream delegate;
+
+    public OutputStreamAdapter(java.io.OutputStream delegate)
+    {
+        this.delegate = delegate;
+    }
+
+    //
+    // IOutputStream
+    //
+    
+    public void write(byte[] b, int off, int len) throws WrappedIOException
+    {
+        try
+        {
+            delegate.write(b, off, len);
+        } catch (IOException ex)
+        {
+            throw new WrappedIOException(ex);
+        }
+    }
+
+    public void write(byte[] b) throws WrappedIOException
+    {
+        try
+        {
+            delegate.write(b);
+        } catch (IOException ex)
+        {
+            throw new WrappedIOException(ex);
+        }
+    }
+
+    public void write(int b) throws WrappedIOException
+    {
+        try
+        {
+            delegate.write(b);
+        } catch (IOException ex)
+        {
+            throw new WrappedIOException(ex);
+        }
+    }
+
+    public void close() throws WrappedIOException
+    {
+        try
+        {
+            delegate.close();
+        } catch (IOException ex)
+        {
+            throw new WrappedIOException(ex);
+        }
+    }
+
+    public void flush() throws WrappedIOException
+    {
+        try
+        {
+            delegate.flush();
+        } catch (IOException ex)
+        {
+            throw new WrappedIOException(ex);
+        }
+    }
+
+    public void synchronize() throws WrappedIOException
+    {
+        flush();
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return delegate.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return delegate.toString();
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/QueueingPathRemoverService.java b/common/source/java/ch/systemsx/cisd/common/filesystem/QueueingPathRemoverService.java
index d6626ce9aa0f09ede234b74912954497d09d0562..f3c03f2612913a1c45e5e49b5f8b2c279396a6a1 100644
--- a/common/source/java/ch/systemsx/cisd/common/filesystem/QueueingPathRemoverService.java
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/QueueingPathRemoverService.java
@@ -22,13 +22,13 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.log4j.Logger;
 
+import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.common.TimingParameters;
 import ch.systemsx.cisd.common.collections.ExtendedBlockingQueueFactory;
 import ch.systemsx.cisd.common.collections.ExtendedLinkedBlockingQueue;
 import ch.systemsx.cisd.common.collections.IExtendedBlockingQueue;
 import ch.systemsx.cisd.common.collections.PersistentExtendedBlockingQueueDecorator;
 import ch.systemsx.cisd.common.collections.RecordBasedQueuePersister;
-import ch.systemsx.cisd.common.concurrent.MonitoringProxy;
 import ch.systemsx.cisd.common.exceptions.StopException;
 import ch.systemsx.cisd.common.logging.ISimpleLogger;
 import ch.systemsx.cisd.common.logging.Log4jSimpleLogger;
@@ -36,8 +36,9 @@ import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 
 /**
- * A service for removing (deep) paths. It provides a {@link IFileRemover} that marks {@link File}s
- * for deletion and queues them up, using a separate thread to actually delete them.
+ * A service for removing (deep) paths. It provides a method {@link #removeRecursively(File)} that
+ * marks {@link File}s for deletion and queues them up, using a separate thread to actually delete
+ * them.
  * <p>
  * Note that the service needs to be started via {@link #start(File, TimingParameters)}.
  * <p>
@@ -46,7 +47,7 @@ import ch.systemsx.cisd.common.logging.LogFactory;
  * 
  * @author Bernd Rinn
  */
-public class QueueingPathRemoverService implements IFileRemover
+public class QueueingPathRemoverService
 {
 
     private final static Logger operationLog =
@@ -54,7 +55,7 @@ public class QueueingPathRemoverService implements IFileRemover
 
     private static final int INITIAL_RECORD_SIZE = 128;
 
-    // @Private
+    @Private
     final static String SHREDDER_PREFIX = ".SHREDDER_";
 
     private static final AtomicInteger counter = new AtomicInteger();
@@ -67,18 +68,6 @@ public class QueueingPathRemoverService implements IFileRemover
 
     private static IFileRemover deepRemover = null;
 
-    private static IFileRemover queueingRemover = null;
-
-    private static QueueingPathRemoverService instance = new QueueingPathRemoverService();
-
-    /**
-     * Returns the instance of the shredder.
-     */
-    public static final QueueingPathRemoverService getInstance()
-    {
-        return instance;
-    }
-
     /**
      * Initializes the shredder thread. Will not persist over program restart. <i>Needs to be called
      * before this class is constructed for the first time.</i>
@@ -107,33 +96,12 @@ public class QueueingPathRemoverService implements IFileRemover
      * @param queueFileOrNull If not <code>null</code>, the file will be used to persist the items
      *            to be deleted over program restart.
      */
-    public static final void start(final File queueFileOrNull, TimingParameters parameters)
+    public static synchronized final void start(final File queueFileOrNull,
+            TimingParameters parameters)
     {
         final ISimpleLogger logger = new Log4jSimpleLogger(operationLog);
         final IFileRemover monitoringProxy = FileOperations.createMonitoredInstance(parameters);
         deepRemover = new LoggingPathRemoverDecorator(monitoringProxy, logger, false);
-        queueingRemover = MonitoringProxy.create(IFileRemover.class, new IFileRemover()
-            {
-                public boolean removeRecursively(File fileToRemove)
-                {
-                    if (fileToRemove.isFile())
-                    {
-                        return fileToRemove.delete();
-                    } else
-                    {
-                        final String name =
-                                SHREDDER_PREFIX + System.currentTimeMillis() + "-"
-                                        + counter.incrementAndGet() + "-" + fileToRemove.getName();
-                        final File shredderFile = new File(fileToRemove.getParentFile(), name);
-                        final boolean ok = fileToRemove.renameTo(shredderFile);
-                        if (ok)
-                        {
-                            queue.add(shredderFile);
-                        }
-                        return ok;
-                    }
-                }
-            }).timing(parameters).errorLog(logger).get();
         if (queueFileOrNull != null)
         {
             final PersistentExtendedBlockingQueueDecorator<File> persistentQueue =
@@ -171,6 +139,33 @@ public class QueueingPathRemoverService implements IFileRemover
         thread.start();
     }
 
+    /**
+     * Deletes <var>fileToRemove</var>, if necessary recursively. If it is a file, it will be
+     * deleted immediately, if it is a directory, it will be queued up for asynchronous deletion.
+     * <p>
+     * <i>This method does not monitor file system operations for hangs. If you need this
+     * functionality, use {@link IFileOperations#removeRecursivelyQueueing(File)} instead!</i>
+     */
+    public static boolean removeRecursively(File fileToRemove)
+    {
+        if (fileToRemove.isFile())
+        {
+            return fileToRemove.delete();
+        } else
+        {
+            final String name =
+                    SHREDDER_PREFIX + System.currentTimeMillis() + "-" + counter.incrementAndGet()
+                            + "-" + fileToRemove.getName();
+            final File shredderFile = new File(fileToRemove.getParentFile(), name);
+            final boolean ok = fileToRemove.renameTo(shredderFile);
+            if (ok)
+            {
+                queue.add(shredderFile);
+            }
+            return ok;
+        }
+    }
+
     private static final void close()
     {
         if (queueCloseableOrNull != null)
@@ -179,7 +174,10 @@ public class QueueingPathRemoverService implements IFileRemover
         }
     }
 
-    public static final void stop()
+    /**
+     * Stop the service.
+     */
+    public static synchronized final void stop()
     {
         thread.interrupt();
         close();
@@ -189,7 +187,13 @@ public class QueueingPathRemoverService implements IFileRemover
         deepRemover = null;
     }
 
-    public static final boolean stopAndWait(long timeoutMillis)
+    /**
+     * Stop the service and wait for it to finish, but at most <var>timeoutMillis</var>
+     * milli-seconds.
+     * 
+     * @return <code>true</code>, if stopping was successful, <code>false</code> otherwise.
+     */
+    public static synchronized final boolean stopAndWait(long timeoutMillis)
     {
         thread.interrupt();
         try
@@ -198,18 +202,24 @@ public class QueueingPathRemoverService implements IFileRemover
         } catch (InterruptedException ex)
         {
         }
-        final boolean ok = (thread.isAlive() == false);
         close();
-        return ok;
+        thread = null;
+        queue = null;
+        queueCloseableOrNull = null;
+        deepRemover = null;
+        return (thread.isAlive() == false);
     }
 
-    public static final boolean isRunning()
+    /**
+     * Returns <code>true</code>, if the service is currently running, <code>false</code> otherwise.
+     */
+    public static synchronized final boolean isRunning()
     {
-        return queueingRemover != null;
+        return deepRemover != null;
     }
-    
+
     /**
-     * Return list of shredder items.
+     * Returns the list of currently queued up shredder items.
      */
     public static final List<File> listShredderItems(File queueFile)
     {
@@ -221,9 +231,4 @@ public class QueueingPathRemoverService implements IFileRemover
         // Cannot be instantiated.
     }
 
-    public boolean removeRecursively(File fileToRemove)
-    {
-        return queueingRemover.removeRecursively(fileToRemove);
-    }
-
 }
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/FileOperationsTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/FileOperationsTest.java
index 20e0c7460bbda0f2a7c89d0790861925cf62c9ba..9cf811f8790e20a6e5eb953217be63d0ad5f37b9 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/FileOperationsTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/FileOperationsTest.java
@@ -23,6 +23,7 @@ import java.io.InputStream;
 
 import org.testng.annotations.Test;
 
+import ch.rinn.restrictions.Friend;
 import ch.systemsx.cisd.common.TimingParameters;
 import ch.systemsx.cisd.common.concurrent.ConcurrencyUtilities;
 import ch.systemsx.cisd.common.concurrent.IActivityObserver;
@@ -37,6 +38,7 @@ import ch.systemsx.cisd.common.logging.Log4jSimpleLogger;
  * 
  * @author Bernd Rinn
  */
+@Friend(toClasses = FileOperations.class)
 public class FileOperationsTest
 {
 
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/QueueingPathRemoverServiceTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/QueueingPathRemoverServiceTest.java
index 8941ec0e10c947d0779fbd08d32bf716f26d9f37..b6f70f734b9c3b885e04f44a66360e63ae0bf956 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/QueueingPathRemoverServiceTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/QueueingPathRemoverServiceTest.java
@@ -59,8 +59,6 @@ public class QueueingPathRemoverServiceTest
             }
         };
 
-    private final QueueingPathRemoverService shredder = QueueingPathRemoverService.getInstance();
-
     @BeforeTest
     public void setUp()
     {
@@ -88,7 +86,7 @@ public class QueueingPathRemoverServiceTest
         f.createNewFile();
         f.deleteOnExit();
         assertTrue(f.exists());
-        shredder.removeRecursively(f);
+        QueueingPathRemoverService.removeRecursively(f);
         assertFalse(f.exists());
         ConcurrencyUtilities.sleep(WAIT_MILLIS);
         assertEquals(0, workingDirectory.list(SHREDDER_FILTER).length);
@@ -108,7 +106,7 @@ public class QueueingPathRemoverServiceTest
             (new File(f, "f" + i)).createNewFile();
         }
         assertTrue(f.exists());
-        shredder.removeRecursively(f);
+        QueueingPathRemoverService.removeRecursively(f);
         assertFalse(f.exists());
         ConcurrencyUtilities.sleep(WAIT_MILLIS);
         assertEquals(0, workingDirectory.list(SHREDDER_FILTER).length);
@@ -126,7 +124,7 @@ public class QueueingPathRemoverServiceTest
         }
         for (File f : list)
         {
-            shredder.removeRecursively(f);
+            QueueingPathRemoverService.removeRecursively(f);
             assertFalse(f.exists());
         }
         ConcurrencyUtilities.sleep(WAIT_MILLIS);
@@ -145,7 +143,7 @@ public class QueueingPathRemoverServiceTest
         }
         for (File f : list)
         {
-            shredder.removeRecursively(f);
+            QueueingPathRemoverService.removeRecursively(f);
             ConcurrencyUtilities.sleep(DELAY_MILLIS);
             assertFalse(f.exists());
         }