diff --git a/common/source/java/ch/systemsx/cisd/common/highwatermark/DirectoryScanningChangeListener.java b/common/source/java/ch/systemsx/cisd/common/highwatermark/DirectoryScanningChangeListener.java
deleted file mode 100644
index 7522a78d6db943ecd5a40f36c228cb155d3471d5..0000000000000000000000000000000000000000
--- a/common/source/java/ch/systemsx/cisd/common/highwatermark/DirectoryScanningChangeListener.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.highwatermark;
-
-import java.io.File;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher.HighwaterMarkEvent;
-import ch.systemsx.cisd.common.utilities.DirectoryScanningTimerTask;
-import ch.systemsx.cisd.common.utilities.StoreItem;
-
-/**
- * A <code>ChangeListener</code> implementation that informs the encapsulated
- * {@link DirectoryScanningTimerTask} when the free space is again OK.
- * <p>
- * Subclasses will fill the unhandled paths set.
- * </p>
- * 
- * @author Christian Ribeaud
- */
-public abstract class DirectoryScanningChangeListener implements ChangeListener
-{
-    private DirectoryScanningTimerTask directoryScanning;
-
-    protected final Set<StoreItem> unhandledItems = new HashSet<StoreItem>();
-
-    protected DirectoryScanningChangeListener()
-    {
-    }
-
-    /**
-     * Encapsulates given <var>path</var> in a <code>StoreItem</code> and returns it.
-     */
-    protected final StoreItem asStoreItem(final File path)
-    {
-        return StoreItem.asItem(path);
-    }
-
-    /**
-     * Sets the <code>DirectoryScanningTimerTask</code> that should get informed (and remove the
-     * unhandled paths from the faulty ones) when free space is again OK.
-     */
-    public final void setDirectoryScanning(final DirectoryScanningTimerTask directoryScanning)
-    {
-        assert directoryScanning != null : "Unspecified DirectoryScanningTimerTask.";
-        this.directoryScanning = directoryScanning;
-    }
-
-    //
-    // ChangeListener
-    //
-
-    public final void stateChanged(final ChangeEvent e)
-    {
-        assert directoryScanning != null : "Unspecified DirectoryScanningTimerTask.";
-        final HighwaterMarkEvent event = (HighwaterMarkEvent) e;
-        if (event.isBelow() == false)
-        {
-            directoryScanning.removeFaultyPaths(unhandledItems.toArray(StoreItem.EMPTY_ARRAY));
-            unhandledItems.clear();
-        }
-    }
-
-}
diff --git a/common/source/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandler.java b/common/source/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e180a24091f31bd27cae171825fc70fcf31430e
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandler.java
@@ -0,0 +1,94 @@
+/*
+ * 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.highwatermark;
+
+import java.io.File;
+
+import ch.systemsx.cisd.common.utilities.DirectoryScanningHandlerInterceptor;
+import ch.systemsx.cisd.common.utilities.IDirectoryScanningHandler;
+import ch.systemsx.cisd.common.utilities.StoreItem;
+import ch.systemsx.cisd.common.utilities.DirectoryScanningTimerTask.IScannedStore;
+
+/**
+ * A <code>DirectoryScanningHandlerInterceptor</code> extension which bases its decision on the
+ * encapsulated {@link HighwaterMarkWatcher} and {@link FileWithHighwaterMark}s.
+ * <p>
+ * Note that the decision has precedence over encapsulated {@link IDirectoryScanningHandler}
+ * implementation and might short-circuit it.
+ * </p>
+ * 
+ * @author Christian Ribeaud
+ */
+public final class HighwaterMarkDirectoryScanningHandler extends
+        DirectoryScanningHandlerInterceptor
+{
+    private final HighwaterMarkWatcher highwaterMarkWatcher;
+
+    private final File[] files;
+
+    public HighwaterMarkDirectoryScanningHandler(
+            final IDirectoryScanningHandler directoryScanningHandler,
+            final HighwaterMarkWatcher highwaterMarkWatcher, final File... files)
+    {
+        super(directoryScanningHandler);
+        assert directoryScanningHandler != null : "Unspecified IDirectoryScanningHandler";
+        assert highwaterMarkWatcher != null : "Unspecified HighwaterMarkWatcher";
+        assert files != null : "Unspecified files";
+        this.highwaterMarkWatcher = highwaterMarkWatcher;
+        this.files = files;
+    }
+
+    private final boolean mayHandle()
+    {
+        if (files.length < 1)
+        {
+            return isBelow();
+        }
+        for (final File file : files)
+        {
+            if (isBelow(file))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private final boolean isBelow()
+    {
+        // The path has probably been set before.
+        highwaterMarkWatcher.run();
+        return highwaterMarkWatcher.isBelow();
+    }
+
+    private final boolean isBelow(final File path)
+    {
+        highwaterMarkWatcher.setPathAndRun(path);
+        return highwaterMarkWatcher.isBelow();
+    }
+
+    //
+    // IDirectoryScanningHandler
+    //
+
+    @Override
+    public final boolean mayHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    {
+        return mayHandle() == false ? false : super.mayHandle(scannedStore, storeItem);
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/highwatermark/PathHandlerInterceptor.java b/common/source/java/ch/systemsx/cisd/common/highwatermark/PathHandlerInterceptor.java
deleted file mode 100644
index 65b6b23ed550e915185823903e75b8f8aa7165a3..0000000000000000000000000000000000000000
--- a/common/source/java/ch/systemsx/cisd/common/highwatermark/PathHandlerInterceptor.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.highwatermark;
-
-import java.io.File;
-
-import ch.systemsx.cisd.common.utilities.IPathHandler;
-
-/**
- * An <code>IPathHandler</code> implementation which collects the unhandled paths before
- * delegating the calls.
- * 
- * @author Christian Ribeaud
- */
-public final class PathHandlerInterceptor extends DirectoryScanningChangeListener implements
-        IPathHandler
-{
-    private final IPathHandler pathHandler;
-
-    public PathHandlerInterceptor(final IPathHandler pathHandler)
-    {
-        this.pathHandler = pathHandler;
-    }
-
-    //
-    // IPathHandler
-    //
-
-    public final void handle(final File path)
-    {
-        pathHandler.handle(path);
-    }
-
-    public final boolean mayHandle(final File path)
-    {
-        final boolean mayHandle = pathHandler.mayHandle(path);
-        if (mayHandle == false)
-        {
-            unhandledItems.add(asStoreItem(path));
-        }
-        return mayHandle;
-    }
-}
\ No newline at end of file
diff --git a/common/source/java/ch/systemsx/cisd/common/highwatermark/StoreHandlerInterceptor.java b/common/source/java/ch/systemsx/cisd/common/highwatermark/StoreHandlerInterceptor.java
deleted file mode 100644
index cd6f45670ddc905231d1b1caf9c9a7e26783c93c..0000000000000000000000000000000000000000
--- a/common/source/java/ch/systemsx/cisd/common/highwatermark/StoreHandlerInterceptor.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.highwatermark;
-
-import ch.systemsx.cisd.common.utilities.IStoreHandler;
-import ch.systemsx.cisd.common.utilities.StoreItem;
-
-/**
- * An <code>IStoreHandler</code> implementation which collects the unhandled store items before
- * delegating the calls.
- * 
- * @author Christian Ribeaud
- */
-public final class StoreHandlerInterceptor extends DirectoryScanningChangeListener implements
-        IStoreHandler
-{
-    private final IStoreHandler storeHandler;
-
-    public StoreHandlerInterceptor(final IStoreHandler storeHandler)
-    {
-        super();
-        this.storeHandler = storeHandler;
-    }
-
-    //
-    // IStoreHandler
-    //
-
-    public final void handle(final StoreItem item)
-    {
-        storeHandler.handle(item);
-    }
-
-    public final boolean mayHandle(final StoreItem item)
-    {
-        final boolean mayHandle = storeHandler.mayHandle(item);
-        if (mayHandle == false)
-        {
-            unhandledItems.add(item);
-        }
-        return mayHandle;
-    }
-
-}
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningHandlerInterceptor.java b/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningHandlerInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..fbb6ae8cfdeb6513bd147d09e9aa0ec99d383992
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningHandlerInterceptor.java
@@ -0,0 +1,56 @@
+/*
+ * 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.utilities;
+
+import ch.systemsx.cisd.common.utilities.DirectoryScanningTimerTask.IScannedStore;
+
+/**
+ * An <code>IDirectoryScanningHandler</code> implementation which simply delegates the method
+ * calls to the encapsulated implementation.
+ * 
+ * @author Christian Ribeaud
+ */
+public class DirectoryScanningHandlerInterceptor implements IDirectoryScanningHandler
+{
+    private final IDirectoryScanningHandler directoryScanningHandler;
+
+    protected DirectoryScanningHandlerInterceptor(
+            final IDirectoryScanningHandler directoryScanningHandler)
+    {
+        assert directoryScanningHandler != null : "Unspecified IDirectoryScanningHandler implementation";
+        this.directoryScanningHandler = directoryScanningHandler;
+    }
+
+    //
+    // IDirectoryScanningHandler
+    //
+
+    public void beforeHandle()
+    {
+        directoryScanningHandler.beforeHandle();
+    }
+
+    public boolean mayHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    {
+        return directoryScanningHandler.mayHandle(scannedStore, storeItem);
+    }
+
+    public void finishItemHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    {
+        directoryScanningHandler.finishItemHandle(scannedStore, storeItem);
+    }
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTask.java b/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTask.java
index 10c7a70be56fb46966d2970bd713c47bf49425fa..d37dc555268a7ae051eb087ea285ac2cdc5fa9b1 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTask.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTask.java
@@ -18,14 +18,10 @@ package ch.systemsx.cisd.common.utilities;
 
 import java.io.File;
 import java.io.FileFilter;
-import java.util.HashSet;
-import java.util.Set;
 import java.util.TimerTask;
 
 import org.apache.log4j.Logger;
 
-import ch.systemsx.cisd.common.collections.CollectionIO;
-import ch.systemsx.cisd.common.collections.CollectionUtils;
 import ch.systemsx.cisd.common.logging.ISimpleLogger;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
@@ -39,21 +35,20 @@ import ch.systemsx.cisd.common.logging.LogLevel;
  * <p>
  * The class should be constructed in the start-up phase and as part of the system's self-test in
  * order to reveal problems with incorrect paths timely.
+ * </p>
  * 
  * @author Bernd Rinn
  */
 public final class DirectoryScanningTimerTask extends TimerTask
 {
 
-    static final String FAULTY_PATH_FILENAME = ".faulty_paths";
-
     private static final Logger operationLog =
             LogFactory.getLogger(LogCategory.OPERATION, DirectoryScanningTimerTask.class);
 
     private static final Logger notificationLog =
             LogFactory.getLogger(LogCategory.NOTIFY, DirectoryScanningTimerTask.class);
 
-    private final IStoreHandler handler;
+    private final IStoreHandler storeHandler;
 
     private final IScannedStore sourceDirectory;
 
@@ -65,11 +60,7 @@ public final class DirectoryScanningTimerTask extends TimerTask
 
     private int errorCountReadingDirectory;
 
-    private final Set<String> faultyPaths;
-
-    private final File faultyPathsFile;
-
-    private long faultyPathsLastChanged;
+    private final IDirectoryScanningHandler directoryScanningHandler;
 
     /**
      * Creates a <var>DirectoryScanningTimerTask</var>.
@@ -77,59 +68,99 @@ public final class DirectoryScanningTimerTask extends TimerTask
      * @param sourceDirectory The directory to scan for entries.
      * @param filter The file filter that picks the entries to handle.
      * @param handler The handler that is used for treating the matching paths.
+     * @param directoryScanningHandler A directory scanning handler.
      */
     public DirectoryScanningTimerTask(final File sourceDirectory, final FileFilter filter,
-            final IPathHandler handler)
+            final IPathHandler handler, final IDirectoryScanningHandler directoryScanningHandler)
     {
-        this(sourceDirectory, filter, handler, 0);
+        this(asScannedStore(sourceDirectory, filter), directoryScanningHandler, PathHandlerAdapter
+                .asScanningHandler(sourceDirectory, handler), 0);
     }
 
     /**
      * Creates a <var>DirectoryScanningTimerTask</var>.
      * 
+     * @param scannedStore The store which is scan for entries.
      * @param sourceDirectory The directory to scan for entries.
-     * @param filter The file filter that picks the entries to handle.
-     * @param handler The handler that is used for treating the matching paths.
+     * @param storeHandler The handler that is used for treating the matching paths.
      * @param ignoredErrorCount The number of consecutive errors of reading the directory that need
      *            to occur before the next error is logged (can be used to suppress error when the
      *            directory is on a remote share and the server is flaky sometimes)
      */
-    public DirectoryScanningTimerTask(final File sourceDirectory, final FileFilter filter,
-            final IPathHandler handler, final int ignoredErrorCount)
+    public DirectoryScanningTimerTask(final IScannedStore scannedStore, final File sourceDirectory,
+            final IStoreHandler storeHandler, final int ignoredErrorCount)
     {
-        this(asScannedStore(sourceDirectory, filter), sourceDirectory, PathHandlerAdapter
-                .asScanningHandler(sourceDirectory, handler), ignoredErrorCount);
+        this(scannedStore, new FaultyPathHandler(sourceDirectory), storeHandler, ignoredErrorCount);
     }
 
+    /**
+     * Creates a <var>DirectoryScanningTimerTask</var>.
+     * 
+     * @param sourceDirectory The directory to scan for entries.
+     * @param storeHandler The handler that is used for treating the matching paths.
+     * @param directoryScanningHandler A directory scanning handler.
+     */
     public DirectoryScanningTimerTask(final File sourceDirectory, final FileFilter filter,
-            final IStoreHandler handler)
+            final IStoreHandler storeHandler,
+            final IDirectoryScanningHandler directoryScanningHandler)
+    {
+        this(asScannedStore(sourceDirectory, filter), directoryScanningHandler, storeHandler, 0);
+    }
+
+    /**
+     * Creates a <var>DirectoryScanningTimerTask</var>.
+     * 
+     * @param sourceDirectory The directory to scan for entries.
+     * @param fileFilter The file filter that picks the entries to handle.
+     * @param pathHandler The handler that is used for treating the matching paths.
+     * @param ignoredErrorCount The number of consecutive errors of reading the directory that need
+     *            to occur before the next error is logged (can be used to suppress error when the
+     *            directory is on a remote share and the server is flaky sometimes)
+     */
+    DirectoryScanningTimerTask(final File sourceDirectory, final FileFilter fileFilter,
+            final IPathHandler pathHandler, final int ignoredErrorCount)
+    {
+        this(asScannedStore(sourceDirectory, fileFilter), new FaultyPathHandler(sourceDirectory),
+                PathHandlerAdapter.asScanningHandler(sourceDirectory, pathHandler),
+                ignoredErrorCount);
+    }
+
+    /**
+     * Creates a <var>DirectoryScanningTimerTask</var>.
+     * 
+     * @param sourceDirectory The directory to scan for entries.
+     * @param filter The file filter that picks the entries to handle.
+     * @param pathHandler The handler that is used for treating the matching paths.
+     */
+    DirectoryScanningTimerTask(final File sourceDirectory, final FileFilter filter,
+            final IPathHandler pathHandler)
     {
-        this(asScannedStore(sourceDirectory, filter), sourceDirectory, handler, 0);
+        this(sourceDirectory, filter, pathHandler, 0);
     }
 
     /**
      * Creates a <var>DirectoryScanningTimerTask</var>.
      * 
      * @param scannedStore The store which is scan for entries.
-     * @param faultyPathDirectory The directory in which file with faulty paths is should be stored.
-     * @param handler The handler that is used for treating the matching paths.
+     * @param directoryScanningHandler A directory scanning handler.
+     * @param storeHandler The handler that is used for treating the matching paths.
      * @param ignoredErrorCount The number of consecutive errors of reading the directory that need
      *            to occur before the next error is logged (can be used to suppress error when the
      *            directory is on a remote share and the server is flaky sometimes)
      */
-    public DirectoryScanningTimerTask(final IScannedStore scannedStore,
-            final File faultyPathDirectory, final IStoreHandler handler, final int ignoredErrorCount)
+    private DirectoryScanningTimerTask(final IScannedStore scannedStore,
+            final IDirectoryScanningHandler directoryScanningHandler,
+            final IStoreHandler storeHandler, final int ignoredErrorCount)
     {
         assert scannedStore != null;
-        assert handler != null;
+        assert storeHandler != null;
+        assert directoryScanningHandler != null : "Unspecified IDirectoryScanningHandler implementation";
         assert ignoredErrorCount >= 0;
 
         this.ignoredErrorCount = ignoredErrorCount;
         this.sourceDirectory = scannedStore;
-        this.handler = handler;
-        this.faultyPaths = new HashSet<String>();
-        this.faultyPathsFile = new File(faultyPathDirectory, FAULTY_PATH_FILENAME);
-        faultyPathsFile.delete();
+        this.storeHandler = storeHandler;
+        this.directoryScanningHandler = directoryScanningHandler;
     }
 
     private final static IScannedStore asScannedStore(final File directory, final FileFilter filter)
@@ -137,50 +168,51 @@ public final class DirectoryScanningTimerTask extends TimerTask
         return new DirectoryScannedStore(filter, directory);
     }
 
-    private final static String getLocationDescription(final File file)
-    {
-        return file.getPath();
-    }
-
     /**
      * Handles all entries in the source directory that are picked by the filter.
      */
     @Override
     public final void run()
     {
+        if (operationLog.isTraceEnabled())
+        {
+            operationLog.trace("Start scanning directory " + sourceDirectory + ".");
+        }
         try
         {
-            if (operationLog.isTraceEnabled())
+            final StoreItem[] storeItems = listStoreItems();
+            directoryScanningHandler.beforeHandle();
+            for (final StoreItem storeItem : storeItems)
             {
-                operationLog.trace("Start scanning directory " + sourceDirectory + ".");
-            }
-            checkForFaultyPathsFileChanged();
-            final StoreItem[] paths = listFiles();
-            for (final StoreItem path : paths)
-            {
-                if (isFaultyPathsFile(path)) // Never touch the faultyPathsFile.
-                {
-                    continue;
-                }
-                try
-                {
-                    handle(path);
-                } catch (final Exception ex) // do not stop when processing of one file has
-                // failed,
-                // continue with other files
+                if (directoryScanningHandler.mayHandle(sourceDirectory, storeItem))
                 {
-                    printNotification(ex);
+                    try
+                    {
+                        storeHandler.handle(storeItem);
+                        if (operationLog.isDebugEnabled())
+                        {
+                            operationLog.debug(String.format(
+                                    "Following store item '%s' has been handled.", storeItem));
+                        }
+                    } catch (final Exception ex)
+                    {
+                        // Do not stop when processing of one file has failed,
+                        // continue with other files.
+                        printNotification(ex);
+                    } finally
+                    {
+                        directoryScanningHandler.finishItemHandle(sourceDirectory, storeItem);
+                    }
                 }
-
-            }
-            if (operationLog.isTraceEnabled())
-            {
-                operationLog.trace("Finished scanning directory " + sourceDirectory + ".");
             }
         } catch (final Exception ex)
         {
             printNotification(ex);
         }
+        if (operationLog.isTraceEnabled())
+        {
+            operationLog.trace("Finished scanning directory " + sourceDirectory + ".");
+        }
     }
 
     private final void printNotification(final Exception ex)
@@ -188,50 +220,17 @@ public final class DirectoryScanningTimerTask extends TimerTask
         notificationLog.error("An exception has occurred. (thread still running)", ex);
     }
 
-    private boolean isFaultyPathsFile(final StoreItem item)
+    private final StoreItem[] listStoreItems()
     {
-        final String itemLocation = sourceDirectory.getLocationDescription(item);
-        final String faultyPathsLocation = getLocationDescription(faultyPathsFile);
-        return itemLocation.equals(faultyPathsLocation);
-    }
-
-    private final void checkForFaultyPathsFileChanged()
-    {
-        if (faultyPathsFile.exists())
-        {
-            if (faultyPathsFile.lastModified() > faultyPathsLastChanged) // Handles manual
-            // manipulation.
-            {
-                faultyPaths.clear();
-                CollectionIO.readCollection(faultyPathsFile, faultyPaths);
-                faultyPathsLastChanged = faultyPathsFile.lastModified();
-                if (operationLog.isInfoEnabled())
-                {
-                    operationLog.info(String.format(
-                            "Reread faulty paths file (%s), new set contains %d entries",
-                            getLocationDescription(faultyPathsFile), faultyPaths.size()));
-                }
-            }
-        } else
-        // Handles manual removal.
-        {
-            faultyPaths.clear();
-        }
-    }
-
-    private final StoreItem[] listFiles()
-    {
-        final boolean logNotifyError = (errorCountReadingDirectory == ignoredErrorCount); // Avoid
-        // mailbox
-        // flooding.
+        // Avoid mailbox flooding.
+        final boolean logNotifyError = (errorCountReadingDirectory == ignoredErrorCount);
         final boolean logOperationError = (errorCountReadingDirectory < ignoredErrorCount);
         final ISimpleLogger errorLogger =
                 logNotifyError ? createSimpleErrorLogger(LogCategory.NOTIFY)
                         : (logOperationError ? createSimpleErrorLogger(LogCategory.OPERATION)
                                 : null);
-
-        final StoreItem[] paths = sourceDirectory.tryListSortedReadyToProcess(errorLogger);
-        if (errorCountReadingDirectory > ignoredErrorCount && paths != null)
+        final StoreItem[] storeItems = sourceDirectory.tryListSortedReadyToProcess(errorLogger);
+        if (errorCountReadingDirectory > ignoredErrorCount && storeItems != null)
         {
             if (notificationLog.isInfoEnabled())
             {
@@ -239,14 +238,14 @@ public final class DirectoryScanningTimerTask extends TimerTask
                         sourceDirectory));
             }
         }
-        if (paths == null)
+        if (storeItems == null)
         {
             ++errorCountReadingDirectory;
         } else
         {
             errorCountReadingDirectory = 0;
         }
-        return (paths == null) ? new StoreItem[0] : paths;
+        return (storeItems == null) ? StoreItem.EMPTY_ARRAY : storeItems;
     }
 
     private final ISimpleLogger createSimpleErrorLogger(final LogCategory category)
@@ -271,79 +270,6 @@ public final class DirectoryScanningTimerTask extends TimerTask
             };
     }
 
-    private final void handle(final StoreItem item)
-    {
-        if (isFaultyPath(item))
-        { // Guard: skip faulty paths.
-            return;
-        }
-        try
-        {
-            final boolean mayHandle = handler.mayHandle(item);
-            if (mayHandle)
-            {
-                handler.handle(item);
-            }
-            if (operationLog.isDebugEnabled())
-            {
-                operationLog.debug(String.format("Following store item '%s' has %sbeen handled.",
-                        item, mayHandle ? "" : "NOT "));
-            }
-        } finally
-        {
-            // If the item still exists, we assume that it has not been handled. So it should be
-            // added to the faulty
-            // paths.
-            if (sourceDirectory.exists(item))
-            {
-                addToFaultyPaths(item);
-            }
-        }
-    }
-
-    private final boolean isFaultyPath(final StoreItem item)
-    {
-        final String path = sourceDirectory.getLocationDescription(item);
-        return faultyPaths.contains(path);
-    }
-
-    private final void addToFaultyPaths(final StoreItem item)
-    {
-        final String path = sourceDirectory.getLocationDescription(item);
-        faultyPaths.add(path);
-        refreshFaultyPathsFile();
-    }
-
-    private final void refreshFaultyPathsFile()
-    {
-        CollectionIO.writeIterable(faultyPathsFile, faultyPaths);
-        faultyPathsLastChanged = faultyPathsFile.lastModified();
-    }
-
-    /** Removes given <var>storeItems</var> from the set of faulty ones. */
-    public final void removeFaultyPaths(final StoreItem... storeItems)
-    {
-        assert storeItems != null : "Unspecified store items.";
-        final int size = storeItems.length;
-        if (size == 0)
-        {
-            return;
-        }
-        final Set<String> paths = new HashSet<String>(size);
-        for (final StoreItem storeItem : storeItems)
-        {
-            paths.add(sourceDirectory.getLocationDescription(storeItem));
-        }
-        faultyPaths.removeAll(paths);
-        if (operationLog.isDebugEnabled())
-        {
-            operationLog.debug(String.format(
-                    "Following paths %s have been removed from the the faulty ones.",
-                    CollectionUtils.abbreviate(paths, 10)));
-        }
-        refreshFaultyPathsFile();
-    }
-
     //
     // Helper classes
     //
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/FaultyPathHandler.java b/common/source/java/ch/systemsx/cisd/common/utilities/FaultyPathHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..c2f9a52c19b43864e312212ca9d32ac7b1718dab
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/FaultyPathHandler.java
@@ -0,0 +1,141 @@
+/*
+ * 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.utilities;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.common.collections.CollectionIO;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.utilities.DirectoryScanningTimerTask.IScannedStore;
+
+/**
+ * An <code>IDirectoryScanningHandler</code> which manages faulty paths.
+ * <p>
+ * A faulty path is a {@link StoreItem} which was <i>not handled</i> (still exists in the
+ * {@link IScannedStore}).
+ * </p>
+ * 
+ * @author Christian Ribeaud
+ */
+public final class FaultyPathHandler implements IDirectoryScanningHandler
+{
+
+    private static final Logger operationLog =
+            LogFactory.getLogger(LogCategory.OPERATION, FaultyPathHandler.class);
+
+    private final Set<String> faultyPaths;
+
+    private final File faultyPathsFile;
+
+    private long faultyPathsLastChanged;
+
+    static final String FAULTY_PATH_FILENAME = ".faulty_paths";
+
+    public FaultyPathHandler(final File faultyPathDirectory)
+    {
+        this.faultyPaths = new HashSet<String>();
+        this.faultyPathsFile = new File(faultyPathDirectory, FAULTY_PATH_FILENAME);
+        faultyPathsFile.delete();
+    }
+
+    private final void checkForFaultyPathsFileChanged()
+    {
+        if (faultyPathsFile.exists())
+        {
+            // Handles manual manipulation.
+            if (faultyPathsFile.lastModified() > faultyPathsLastChanged)
+            {
+                faultyPaths.clear();
+                CollectionIO.readCollection(faultyPathsFile, faultyPaths);
+                faultyPathsLastChanged = faultyPathsFile.lastModified();
+                if (operationLog.isInfoEnabled())
+                {
+                    operationLog.info(String.format(
+                            "Reread faulty paths file (%s), new set contains %d entries",
+                            getLocationDescription(faultyPathsFile), faultyPaths.size()));
+                }
+            }
+        } else
+        {
+            // Handles manual removal.
+            faultyPaths.clear();
+        }
+    }
+
+    private final static String getLocationDescription(final File file)
+    {
+        return file.getPath();
+    }
+
+    private final boolean isFaultyPath(final IScannedStore scannedStore, final StoreItem storeItem)
+    {
+        final String path = scannedStore.getLocationDescription(storeItem);
+        return faultyPaths.contains(path);
+    }
+
+    private final boolean isFaultyPathsFile(final IScannedStore scannedStore,
+            final StoreItem storeItem)
+    {
+        final String itemLocation = scannedStore.getLocationDescription(storeItem);
+        final String faultyPathsLocation = getLocationDescription(faultyPathsFile);
+        return itemLocation.equals(faultyPathsLocation);
+    }
+
+    private final void addToFaultyPaths(final IScannedStore scannedStore, final StoreItem item)
+    {
+        final String path = scannedStore.getLocationDescription(item);
+        faultyPaths.add(path);
+        refreshFaultyPathsFile();
+    }
+
+    private final void refreshFaultyPathsFile()
+    {
+        CollectionIO.writeIterable(faultyPathsFile, faultyPaths);
+        faultyPathsLastChanged = faultyPathsFile.lastModified();
+    }
+
+    //
+    // IDirectoryScanningHandler
+    //
+
+    public final void beforeHandle()
+    {
+        checkForFaultyPathsFileChanged();
+    }
+
+    public final boolean mayHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    {
+        return isFaultyPath(scannedStore, storeItem) == false
+                && isFaultyPathsFile(scannedStore, storeItem) == false;
+    }
+
+    public final void finishItemHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    {
+        // If the item still exists, we assume that it has not been handled. So it
+        // should be added to the faulty paths.
+        if (scannedStore.exists(storeItem))
+        {
+            addToFaultyPaths(scannedStore, storeItem);
+        }
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/IDirectoryScanningHandler.java b/common/source/java/ch/systemsx/cisd/common/utilities/IDirectoryScanningHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..db98d072f454f3c8512cffb88fa160ca7374805d
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/IDirectoryScanningHandler.java
@@ -0,0 +1,46 @@
+/*
+ * 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.utilities;
+
+import ch.systemsx.cisd.common.utilities.DirectoryScanningTimerTask.IScannedStore;
+
+/**
+ * A helper class for {@link DirectoryScanningTimerTask} which performs operations before and after
+ * treating the matching paths.
+ * 
+ * @author Christian Ribeaud
+ * @see DirectoryScanningTimerTask
+ */
+public interface IDirectoryScanningHandler
+{
+
+    /**
+     * Is performed just before handling all the items contained in the store.
+     */
+    public void beforeHandle();
+
+    /**
+     * Whether given <code>storeItem</code> found in given <var>scannedStore</var> should be
+     * processed or not.
+     */
+    public boolean mayHandle(IScannedStore scannedStore, StoreItem storeItem);
+
+    /**
+     * Finishes and closes the handling of given <var>storeItem</var>.
+     */
+    public void finishItemHandle(IScannedStore scannedStore, StoreItem storeItem);
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/IPathHandler.java b/common/source/java/ch/systemsx/cisd/common/utilities/IPathHandler.java
index d775b9049a87fa6e27ea523577c001caf04d4a9b..3380e2f31d489474eb6c0f791bbcb55725274bde 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/IPathHandler.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/IPathHandler.java
@@ -32,12 +32,4 @@ public interface IPathHandler
      * when the method returns.
      */
     public void handle(File path);
-
-    /**
-     * Whether given <var>path</var> may be handled or not.
-     * <p>
-     * This method is called just before {@link #handle(File)}.
-     * </p>
-     */
-    public boolean mayHandle(File path);
 }
\ No newline at end of file
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/IStoreHandler.java b/common/source/java/ch/systemsx/cisd/common/utilities/IStoreHandler.java
index 28a8a9c8a811f4e60ec0a300f9990a51dff09440..0ff94bca6176c7ab7ba3abc252a523e982462ce2 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/IStoreHandler.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/IStoreHandler.java
@@ -35,12 +35,4 @@ public interface IStoreHandler
      * gone when the method returns.
      */
     void handle(StoreItem item);
-
-    /**
-     * Whether given <var>item</var> may be handled or not.
-     * <p>
-     * This method is called just before {@link #handle(StoreItem)}.
-     * </p>
-     */
-    boolean mayHandle(StoreItem item);
 }
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/PathHandlerAdapter.java b/common/source/java/ch/systemsx/cisd/common/utilities/PathHandlerAdapter.java
index 1d3e9b23be17f46331dc24ce98d6dd8b787c1308..43e0a20ce9d5492b94f8ea8fd45bfb2e63dd4b2d 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/PathHandlerAdapter.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/PathHandlerAdapter.java
@@ -49,11 +49,6 @@ public class PathHandlerAdapter implements IStoreHandler
     // IStoreHandler
     //
 
-    public final boolean mayHandle(final StoreItem item)
-    {
-        return pathHandler.mayHandle(asFile(item));
-    }
-
     public final void handle(final StoreItem item)
     {
         pathHandler.handle(asFile(item));
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandlerTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandlerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..94502ec2d320bbb9b40d360faeeda9ba995a801d
--- /dev/null
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandlerTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.highwatermark;
+
+import static org.testng.AssertJUnit.assertFalse;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test cases for the {@link HighwaterMarkDirectoryScanningHandler}.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class HighwaterMarkDirectoryScanningHandlerTest
+{
+
+    @Test
+    public final void testConstructor()
+    {
+        boolean fail = true;
+        try
+        {
+            new HighwaterMarkDirectoryScanningHandler(null, null);
+        } catch (final AssertionError ex)
+        {
+            fail = false;
+        }
+        assertFalse(fail);
+    }
+}
\ No newline at end of file
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTaskTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTaskTest.java
index 5e9bb5ff9f67427f60a06445cc092f9444770fc0..ad72e75ef7ad4097b9e151cb606840de38378c51 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTaskTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTaskTest.java
@@ -78,18 +78,11 @@ public class DirectoryScanningTimerTaskTest
 
         private final List<File> handledPaths = new ArrayList<File>();
 
-        private boolean mayHandle = true;
-
         public void clear()
         {
             handledPaths.clear();
         }
 
-        public final void setMayHandle(final boolean mayHandle)
-        {
-            this.mayHandle = mayHandle;
-        }
-
         //
         // IPathHandler
         //
@@ -99,12 +92,6 @@ public class DirectoryScanningTimerTaskTest
             handledPaths.add(path);
             path.delete();
         }
-
-        public final boolean mayHandle(final File path)
-        {
-            return mayHandle;
-        }
-
     }
 
     @BeforeClass
@@ -126,8 +113,7 @@ public class DirectoryScanningTimerTaskTest
 
     private final File getFaultyPathFile()
     {
-        final File faultyPaths =
-                new File(workingDirectory, DirectoryScanningTimerTask.FAULTY_PATH_FILENAME);
+        final File faultyPaths = new File(workingDirectory, FaultyPathHandler.FAULTY_PATH_FILENAME);
         return faultyPaths;
     }
 
@@ -422,35 +408,4 @@ public class DirectoryScanningTimerTaskTest
             LogMonitoringAppender.removeAppender(appender);
         }
     }
-
-    @Test
-    public final void testRemoveFaultyPaths() throws IOException
-    {
-        final MockPathHandler pathHandler = new MockPathHandler();
-        pathHandler.setMayHandle(false);
-        final DirectoryScanningTimerTask directoryScanning =
-                new DirectoryScanningTimerTask(workingDirectory, ACCEPT_ALL_FILTER, pathHandler);
-        testPathOrder();
-        // No faulty file at this point.
-        assertEquals(1, workingDirectory.listFiles().length);
-        directoryScanning.run();
-        // One faulty file found (as mayHandle is set to false).
-        List<String> faulty = CollectionIO.readList(getFaultyPathFile());
-        assertEquals(1, faulty.size());
-        final File file = new File(faulty.get(0));
-        directoryScanning.removeFaultyPaths(StoreItem.asItem(file));
-        faulty = CollectionIO.readList(getFaultyPathFile());
-        // Faulty file is empty.
-        assertEquals(0, faulty.size());
-        // Two files found (inclusive the faulty file).
-        assertEquals(2, workingDirectory.listFiles().length);
-        pathHandler.setMayHandle(true);
-        directoryScanning.run();
-        faulty = CollectionIO.readList(getFaultyPathFile());
-        assertEquals(0, faulty.size());
-        // Only the faulty file present now.
-        final File[] files = workingDirectory.listFiles();
-        assertEquals(1, files.length);
-        assertEquals(DirectoryScanningTimerTask.FAULTY_PATH_FILENAME, files[0].getName());
-    }
 }