From 96e7977f161375c95acafb44d484996f6b930b40 Mon Sep 17 00:00:00 2001
From: brinn <brinn>
Date: Thu, 28 Jun 2012 11:43:50 +0000
Subject: [PATCH] Add support for logging dropbox activity. If enabled, a file
 will be touched whenever DirectoryScanningTimerTask starts a processing
 round.

SVN: 25922
---
 .../DirectoryScanningTimerTask.java           | 104 +++++++++++++++++-
 .../DirectoryScanningTimerTaskTest.java       |  10 +-
 2 files changed, 108 insertions(+), 6 deletions(-)

diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/DirectoryScanningTimerTask.java b/common/source/java/ch/systemsx/cisd/common/filesystem/DirectoryScanningTimerTask.java
index adb6359ff8f..e8d2ca3102f 100644
--- a/common/source/java/ch/systemsx/cisd/common/filesystem/DirectoryScanningTimerTask.java
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/DirectoryScanningTimerTask.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.common.filesystem;
 
 import java.io.File;
 import java.io.FileFilter;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -26,6 +27,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.TimerTask;
 
+import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Level;
@@ -79,6 +81,8 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
 
     private String threadNameOrNull;
 
+    private File activityLogDirectoryOrNull;
+
     /**
      * Indicates that we should try to exit the {@link #run()} method as soon as possible.
      * <p>
@@ -87,6 +91,24 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
      */
     private volatile boolean stopRun;
 
+    /**
+     * 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 handler The handler that is used for treating the matching paths.
+     * @param directoryScanningHandler A directory scanning handler.
+     * @param threadName The name of the thread
+     * @param activityLogDirectory The directory to log activity to.
+     */
+    public DirectoryScanningTimerTask(final File sourceDirectory, final FileFilter filter,
+            final IPathHandler handler, final IDirectoryScanningHandler directoryScanningHandler,
+            final String threadName, final File activityLogDirectory)
+    {
+        this(asScannedStore(sourceDirectory, filter), directoryScanningHandler, PathHandlerAdapter
+                .asScanningHandler(sourceDirectory, handler), 0, threadName, activityLogDirectory);
+    }
+
     /**
      * Creates a <var>DirectoryScanningTimerTask</var>.
      * 
@@ -99,7 +121,7 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
             final IPathHandler handler, final IDirectoryScanningHandler directoryScanningHandler)
     {
         this(asScannedStore(sourceDirectory, filter), directoryScanningHandler, PathHandlerAdapter
-                .asScanningHandler(sourceDirectory, handler), 0);
+                .asScanningHandler(sourceDirectory, handler), 0, null, null);
     }
 
     /**
@@ -113,7 +135,8 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
             final IStoreHandler storeHandler,
             final IDirectoryScanningHandler directoryScanningHandler)
     {
-        this(asScannedStore(sourceDirectory, filter), directoryScanningHandler, storeHandler, 0);
+        this(asScannedStore(sourceDirectory, filter), directoryScanningHandler, storeHandler, 0,
+                null, null);
     }
 
     /**
@@ -129,6 +152,21 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
         this(sourceDirectory, filter, pathHandler, 0);
     }
 
+    /**
+     * 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.
+     * @param threadName The name of the thread
+     * @param activityLogDirectory The directory to log activity to.
+     */
+    public DirectoryScanningTimerTask(final File sourceDirectory, final FileFilter filter,
+            final IPathHandler pathHandler, String threadName, File activityLogDirectory)
+    {
+        this(sourceDirectory, filter, pathHandler, 0, threadName, activityLogDirectory);
+    }
+
     /**
      * Creates a <var>DirectoryScanningTimerTask</var>.
      * 
@@ -138,10 +176,13 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
      * @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)
+     * @param threadName The name of the thread
+     * @param activityLogDirectory The directory to log activity to.
      */
     public DirectoryScanningTimerTask(final IScannedStore scannedStore,
             final IDirectoryScanningHandler directoryScanningHandler,
-            final IStoreHandler storeHandler, final int ignoredErrorCount)
+            final IStoreHandler storeHandler, final int ignoredErrorCount, final String threadName,
+            final File activityLogDirectory)
     {
         assert scannedStore != null;
         assert storeHandler != null;
@@ -155,6 +196,17 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
                 new ConditionalNotificationLogger(operationLog, Level.WARN, notificationLog,
                         ignoredErrorCount);
         this.errorLog = new LinkedHashMap<StoreItem, String>();
+        this.threadNameOrNull = threadName;
+        this.activityLogDirectoryOrNull = activityLogDirectory;
+        if (activityLogDirectory != null && activityLogDirectory.isDirectory() == false)
+        {
+            activityLogDirectory.mkdirs();
+            if (activityLogDirectory.isDirectory() == false)
+            {
+                operationLog.error("Cannot create activityLogDirectory " + activityLogDirectory
+                        + " - activity logging disabled.");
+            }
+        }
     }
 
     /**
@@ -172,7 +224,28 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
     {
         this(asScannedStore(sourceDirectory, fileFilter), new FaultyPathDirectoryScanningHandler(
                 sourceDirectory, pathHandler, null), PathHandlerAdapter.asScanningHandler(
-                sourceDirectory, pathHandler), ignoredErrorCount);
+                sourceDirectory, pathHandler), ignoredErrorCount, null, null);
+    }
+
+    /**
+     * 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)
+     * @param threadName The name of the thread
+     * @param activityLogDirectory The directory to log activity to.
+     */
+    DirectoryScanningTimerTask(final File sourceDirectory, final FileFilter fileFilter,
+            final IPathHandler pathHandler, final int ignoredErrorCount, final String threadName,
+            final File activityLogDirectory)
+    {
+        this(asScannedStore(sourceDirectory, fileFilter), new FaultyPathDirectoryScanningHandler(
+                sourceDirectory, pathHandler, null), PathHandlerAdapter.asScanningHandler(
+                sourceDirectory, pathHandler), ignoredErrorCount, threadName, activityLogDirectory);
     }
 
     private final static IScannedStore asScannedStore(final File directory, final FileFilter filter)
@@ -225,7 +298,11 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
         {
             operationLog.trace(String.format("Start scanning directory '%s'.", sourceDirectory));
         }
-        threadNameOrNull = Thread.currentThread().getName();
+        if (threadNameOrNull == null)
+        {
+            threadNameOrNull = Thread.currentThread().getName();
+        }
+        logActivity();
         try
         {
             didSomeWork = false;
@@ -366,6 +443,23 @@ public final class DirectoryScanningTimerTask extends TimerTask implements ITime
         }
     }
 
+    private void logActivity()
+    {
+        if (activityLogDirectoryOrNull != null)
+        {
+            final File activityFile =
+                    new File(activityLogDirectoryOrNull, threadNameOrNull.replace(' ',
+                            '_'));
+            try
+            {
+                FileUtils.touch(activityFile);
+            } catch (IOException ex)
+            {
+                operationLog.warn("Cannot touch activity file " + activityFile);
+            }
+        }
+    }
+
     private void cleanseErrorLog(StoreItem[] allStoreItemsOrNull)
     {
         if (allStoreItemsOrNull == null)
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/DirectoryScanningTimerTaskTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/DirectoryScanningTimerTaskTest.java
index f1d82cdbd6b..b413e8bf40a 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/DirectoryScanningTimerTaskTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/DirectoryScanningTimerTaskTest.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.common.filesystem;
 
 import static ch.systemsx.cisd.common.filesystem.FileUtilities.ACCEPT_ALL_FILTER;
+import static ch.systemsx.cisd.common.filesystem.FileUtilities.ACCEPT_ALL_BUT_HIDDEN_FILTER;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
@@ -149,12 +150,19 @@ public class DirectoryScanningTimerTaskTest
     {
         final File someFile = new File(workingDirectory, "some_file");
         createNewFile(someFile);
+        final File activityLogDir = new File(workingDirectory, ".activity_log");
+        final String threadName = "abc_test";
         final DirectoryScanningTimerTask scanner =
-                new DirectoryScanningTimerTask(workingDirectory, ACCEPT_ALL_FILTER, mockPathHandler);
+                new DirectoryScanningTimerTask(workingDirectory, ACCEPT_ALL_BUT_HIDDEN_FILTER,
+                        mockPathHandler, threadName, activityLogDir);
         assertEquals(0, mockPathHandler.handledPaths.size());
         scanner.run();
         assertEquals(1, mockPathHandler.handledPaths.size());
         assertEquals(someFile, mockPathHandler.handledPaths.get(0));
+        final File activityLogFile = new File(activityLogDir, threadName);
+        assertTrue(activityLogFile.exists());
+        final long milliDiff = System.currentTimeMillis() - activityLogFile.lastModified(); 
+        assertTrue(milliDiff + "ms", milliDiff < 1000);
     }
 
     @Test
-- 
GitLab