From 253d461d78c5f3f5983143c4e1e34123f608b07c Mon Sep 17 00:00:00 2001
From: brinn <brinn>
Date: Mon, 14 Jul 2008 07:52:55 +0000
Subject: [PATCH] [DMV-31] add support for detection and signaling of errors

SVN: 7201
---
 ...HighwaterMarkDirectoryScanningHandler.java |  5 +-
 .../DirectoryScanningHandlerInterceptor.java  |  6 +-
 .../utilities/DirectoryScanningTimerTask.java | 62 +++++++++++++++----
 .../FaultyPathDirectoryScanningHandler.java   | 20 ++++--
 .../utilities/IDirectoryScanningHandler.java  | 17 ++++-
 .../utilities/ITimerTaskStatusProvider.java   | 31 ++++++++++
 .../TimerTaskWithListenersTest.java           |  4 +-
 ...waterMarkDirectoryScanningHandlerTest.java |  7 ++-
 8 files changed, 125 insertions(+), 27 deletions(-)
 create mode 100644 common/source/java/ch/systemsx/cisd/common/utilities/ITimerTaskStatusProvider.java

diff --git a/common/source/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandler.java b/common/source/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandler.java
index 9648758b4d2..f252714d3f4 100644
--- a/common/source/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandler.java
+++ b/common/source/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandler.java
@@ -86,9 +86,10 @@ public final class HighwaterMarkDirectoryScanningHandler extends
     //
 
     @Override
-    public final boolean mayHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    public HandleInstruction mayHandle(final IScannedStore scannedStore, final StoreItem storeItem)
     {
-        return mayHandle() == false ? false : super.mayHandle(scannedStore, storeItem);
+        return mayHandle() == false ? HandleInstruction.ERROR : super.mayHandle(
+                scannedStore, storeItem);
     }
 
 }
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningHandlerInterceptor.java b/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningHandlerInterceptor.java
index fbb6ae8cfde..55205035ed2 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningHandlerInterceptor.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningHandlerInterceptor.java
@@ -44,13 +44,13 @@ public class DirectoryScanningHandlerInterceptor implements IDirectoryScanningHa
         directoryScanningHandler.beforeHandle();
     }
 
-    public boolean mayHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    public HandleInstruction mayHandle(final IScannedStore scannedStore, final StoreItem storeItem)
     {
         return directoryScanningHandler.mayHandle(scannedStore, storeItem);
     }
 
-    public void finishItemHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    public boolean finishItemHandle(final IScannedStore scannedStore, final StoreItem storeItem)
     {
-        directoryScanningHandler.finishItemHandle(scannedStore, storeItem);
+        return 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 769987aa139..df5e3cf1574 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTask.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/DirectoryScanningTimerTask.java
@@ -29,6 +29,7 @@ import ch.systemsx.cisd.common.logging.ConditionalNotificationLogger;
 import ch.systemsx.cisd.common.logging.ISimpleLogger;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.utilities.IDirectoryScanningHandler.HandleInstruction;
 
 /**
  * A {@link TimerTask} that scans a source directory for entries that are accepted by some
@@ -42,7 +43,7 @@ import ch.systemsx.cisd.common.logging.LogFactory;
  * 
  * @author Bernd Rinn
  */
-public final class DirectoryScanningTimerTask extends TimerTask
+public final class DirectoryScanningTimerTask extends TimerTask implements ITimerTaskStatusProvider
 {
 
     private static final Logger operationLog =
@@ -59,6 +60,10 @@ public final class DirectoryScanningTimerTask extends TimerTask
 
     private final ConditionalNotificationLogger notificationLogger;
 
+    private int numberOfProcessedItems;
+
+    private int numberOfErrorItems;
+
     /**
      * Indicates that we should try to exit the {@link #run()} method as soon as possible.
      * <p>
@@ -200,12 +205,14 @@ public final class DirectoryScanningTimerTask extends TimerTask
         }
         try
         {
-            int numberOfItemsHandled;
+            numberOfProcessedItems = 0;
+            numberOfErrorItems = 0;
+            int numberOfItemsProcessedInLastRound;
             do
             {
+                numberOfItemsProcessedInLastRound = 0;
                 final StoreItem[] storeItems = listStoreItems();
                 final int numberOfItems = storeItems.length;
-                numberOfItemsHandled = numberOfItems;
                 directoryScanningHandler.beforeHandle();
                 for (int i = 0; i < numberOfItems; i++)
                 {
@@ -214,14 +221,17 @@ public final class DirectoryScanningTimerTask extends TimerTask
                     {
                         if (operationLog.isDebugEnabled())
                         {
-                            operationLog.debug(String.format("Scan of store '%s' has been cancelled. "
-                                    + "Following items have NOT been handled: %s.", sourceDirectory,
-                                    CollectionUtils.abbreviate(ArrayUtils.subarray(storeItems, i + 1,
-                                            numberOfItems), 10)));
+                            operationLog.debug(String.format(
+                                    "Scan of store '%s' has been cancelled. "
+                                            + "Following items have NOT been handled: %s.",
+                                    sourceDirectory, CollectionUtils.abbreviate(ArrayUtils
+                                            .subarray(storeItems, i + 1, numberOfItems), 10)));
                         }
                         return;
                     }
-                    if (directoryScanningHandler.mayHandle(sourceDirectory, storeItem))
+                    final HandleInstruction instruction =
+                            directoryScanningHandler.mayHandle(sourceDirectory, storeItem);
+                    if (HandleInstruction.PROCESS.equals(instruction))
                     {
                         try
                         {
@@ -231,26 +241,39 @@ public final class DirectoryScanningTimerTask extends TimerTask
                                 operationLog.trace(String.format(
                                         "Following store item '%s' has been handled.", storeItem));
                             }
+                            ++numberOfProcessedItems;
+                            ++numberOfItemsProcessedInLastRound;
                         } catch (final Exception ex)
                         {
                             // Do not stop when processing of one file has failed,
                             // continue with other files.
+                            ++numberOfErrorItems;
                             printNotification(ex);
                         } finally
                         {
-                            directoryScanningHandler.finishItemHandle(sourceDirectory, storeItem);
+                            final boolean ok =
+                                    directoryScanningHandler.finishItemHandle(sourceDirectory,
+                                            storeItem);
+                            if (ok == false)
+                            {
+                                ++numberOfErrorItems;
+                            }
                         }
                     } else
                     {
-                        --numberOfItemsHandled;
+                        if (HandleInstruction.ERROR.equals(instruction))
+                        {
+                            ++numberOfErrorItems;
+                        }
                         if (operationLog.isTraceEnabled())
                         {
                             operationLog.trace(String.format(
-                                    "Following store item '%s' has NOT been handled.", storeItem));
+                                    "Following store item '%s' has NOT been handled (%s).",
+                                    storeItem, instruction));
                         }
                     }
                 }
-            } while (numberOfItemsHandled > 0);
+            } while (numberOfItemsProcessedInLastRound > 0);
         } catch (final Exception ex)
         {
             printNotification(ex);
@@ -261,6 +284,20 @@ public final class DirectoryScanningTimerTask extends TimerTask
         }
     }
 
+    //
+    // ITimerTaskStatusProvider
+    //
+
+    public boolean hasErrors()
+    {
+        return (numberOfErrorItems > 0);
+    }
+
+    public boolean hasPerformedMeaningfulWork()
+    {
+        return (numberOfProcessedItems > 0);
+    }
+
     //
     // Helper classes
     //
@@ -283,4 +320,5 @@ public final class DirectoryScanningTimerTask extends TimerTask
          */
         String getLocationDescription(StoreItem item);
     }
+
 }
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/FaultyPathDirectoryScanningHandler.java b/common/source/java/ch/systemsx/cisd/common/utilities/FaultyPathDirectoryScanningHandler.java
index f2d036d69b4..d4c62e3586d 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/FaultyPathDirectoryScanningHandler.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/FaultyPathDirectoryScanningHandler.java
@@ -129,19 +129,31 @@ public final class FaultyPathDirectoryScanningHandler implements IDirectoryScann
         checkForFaultyPathsFileChanged();
     }
 
-    public final boolean mayHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    public final HandleInstruction mayHandle(final IScannedStore scannedStore, final StoreItem storeItem)
     {
-        return isFaultyPath(scannedStore, storeItem) == false
-                && isFaultyPathsFile(scannedStore, storeItem) == false;
+        if (isFaultyPathsFile(scannedStore, storeItem))
+        {
+            return HandleInstruction.IGNORE;
+        } else if (isFaultyPath(scannedStore, storeItem))
+        {
+            return HandleInstruction.ERROR;
+        } else
+        {
+            return HandleInstruction.PROCESS;
+        }
     }
 
-    public final void finishItemHandle(final IScannedStore scannedStore, final StoreItem storeItem)
+    public final boolean 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.existsOrError(storeItem))
         {
             addToFaultyPaths(scannedStore, storeItem);
+            return false;
+        } else
+        {
+            return true;
         }
     }
 
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/IDirectoryScanningHandler.java b/common/source/java/ch/systemsx/cisd/common/utilities/IDirectoryScanningHandler.java
index db98d072f45..3c794f1a46a 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/IDirectoryScanningHandler.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/IDirectoryScanningHandler.java
@@ -28,6 +28,14 @@ import ch.systemsx.cisd.common.utilities.DirectoryScanningTimerTask.IScannedStor
 public interface IDirectoryScanningHandler
 {
 
+    /**
+     * The instruction of whether to process an item or not.
+     */
+    public enum HandleInstruction
+    {
+        PROCESS, IGNORE, ERROR
+    }
+
     /**
      * Is performed just before handling all the items contained in the store.
      */
@@ -35,12 +43,15 @@ public interface IDirectoryScanningHandler
 
     /**
      * Whether given <code>storeItem</code> found in given <var>scannedStore</var> should be
-     * processed or not.
+     * processed or not, and whether not processing it constitues an error or not.
      */
-    public boolean mayHandle(IScannedStore scannedStore, StoreItem storeItem);
+    public HandleInstruction mayHandle(IScannedStore scannedStore, StoreItem storeItem);
 
     /**
      * Finishes and closes the handling of given <var>storeItem</var>.
+     * 
+     * @returns <code>true</code>, if the item has been handled correctly and <code>false</code>
+     *          if an error occurred.
      */
-    public void finishItemHandle(IScannedStore scannedStore, StoreItem storeItem);
+    public boolean finishItemHandle(IScannedStore scannedStore, StoreItem storeItem);
 }
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/ITimerTaskStatusProvider.java b/common/source/java/ch/systemsx/cisd/common/utilities/ITimerTaskStatusProvider.java
new file mode 100644
index 00000000000..380baa0a096
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/ITimerTaskStatusProvider.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+/**
+ * A provider for status information about the last run of a {@link java.util.TimerTask}. 
+ *
+ * @author Bernd Rinn
+ */
+public interface ITimerTaskStatusProvider
+{
+    
+    public boolean hasPerformedMeaningfulWork();
+    
+    public boolean hasErrors();
+
+}
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/concurrent/TimerTaskWithListenersTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/concurrent/TimerTaskWithListenersTest.java
index eb26e2c9e51..ff5b01ca487 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/concurrent/TimerTaskWithListenersTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/concurrent/TimerTaskWithListenersTest.java
@@ -25,6 +25,8 @@ import java.util.TimerTask;
 
 import org.testng.annotations.Test;
 
+import ch.systemsx.cisd.common.utilities.ITimerTaskStatusProvider;
+
 /**
  * 
  *
@@ -77,7 +79,7 @@ public class TimerTaskWithListenersTest
             recorder.add(name + ".canceling");
         }
 
-        public void finishRunning()
+        public void finishRunning(ITimerTaskStatusProvider statusProviderOrNull)
         {
             recorder.add(name + ".finishRunning");
         }
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandlerTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandlerTest.java
index ef6a2def7a4..2bcf3fb5952 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandlerTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/highwatermark/HighwaterMarkDirectoryScanningHandlerTest.java
@@ -33,6 +33,7 @@ import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher.IFreeSpaceProv
 import ch.systemsx.cisd.common.utilities.IDirectoryScanningHandler;
 import ch.systemsx.cisd.common.utilities.StoreItem;
 import ch.systemsx.cisd.common.utilities.DirectoryScanningTimerTask.IScannedStore;
+import ch.systemsx.cisd.common.utilities.IDirectoryScanningHandler.HandleInstruction;
 
 /**
  * Test cases for the {@link HighwaterMarkDirectoryScanningHandler}.
@@ -134,7 +135,8 @@ public final class HighwaterMarkDirectoryScanningHandlerTest
                     }
                 }
             });
-        boolean mayHandle = scanningHandler.mayHandle(scannedStore, storeItem);
+        boolean mayHandle =
+                HandleInstruction.PROCESS.equals(scanningHandler.mayHandle(scannedStore, storeItem));
         assertEquals(freeSpace > HIGHWATER_MARK, mayHandle);
         context.assertIsSatisfied();
     }
@@ -163,7 +165,8 @@ public final class HighwaterMarkDirectoryScanningHandlerTest
                     }
                 }
             });
-        boolean mayHandle = scanningHandler.mayHandle(scannedStore, storeItem);
+        boolean mayHandle =
+                HandleInstruction.PROCESS.equals(scanningHandler.mayHandle(scannedStore, storeItem));
         assertEquals(freeSpace > HIGHWATER_MARK, mayHandle);
         context.assertIsSatisfied();
     }
-- 
GitLab