From 3636224c227fba437aad985caec21100000d3325 Mon Sep 17 00:00:00 2001
From: brinn <brinn>
Date: Fri, 31 Aug 2007 15:30:03 +0000
Subject: [PATCH] move: IntraFSPathMover to datamover, since it is now more
 datamover specific fix: recovery problem in copy_complete when incoming is
 local add: support for prefix-for-incoming parameter (DMV-6)

SVN: 1566
---
 datamover/dist/etc/service.properties         |  4 +-
 .../cisd/datamover/IntraFSPathMover.java      | 84 +++++++++++++++++++
 .../cisd/datamover/MonitorStarter.java        | 33 ++++----
 .../systemsx/cisd/datamover/Parameters.java   | 18 ++++
 .../datamover/helper/FileSystemHelper.java    | 58 +++++++++++--
 5 files changed, 173 insertions(+), 24 deletions(-)
 create mode 100644 datamover/source/java/ch/systemsx/cisd/datamover/IntraFSPathMover.java

diff --git a/datamover/dist/etc/service.properties b/datamover/dist/etc/service.properties
index 4ad21ade5f4..d8c061369b2 100644
--- a/datamover/dist/etc/service.properties
+++ b/datamover/dist/etc/service.properties
@@ -6,6 +6,7 @@ incoming-dir = data/incoming
 buffer-dir = data/buffer
 outgoing-dir = data/outgoing
 manual-intervention-dir = data/manual_intervention
+prefix-for-incoming = %t_
 
 #
 # Optional (remove comments when changing the values)
@@ -23,4 +24,5 @@ manual-intervention-dir = data/manual_intervention
 # cleansing-regex = <regex of paths that should be removed before moving a path to outgoing>
 # manual-intervention-regex = <regex of paths that need manual intervention>
 # treat-incoming-as-remote = <true or false, when switched on, than incoming directory is treated as remote> 
-# extra-copy-dir = <path to a directory. If specified, a copy of incoming data will be made there>
\ No newline at end of file
+# extra-copy-dir = <path to a directory. If specified, a copy of incoming data will be made there>
+# prefix-for-incoming = prefix that is put in front of every incoming data directory, %t will be replaced with time stamp
\ No newline at end of file
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/IntraFSPathMover.java b/datamover/source/java/ch/systemsx/cisd/datamover/IntraFSPathMover.java
new file mode 100644
index 00000000000..3e74872d603
--- /dev/null
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/IntraFSPathMover.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2007 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.datamover;
+
+import java.io.File;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.utilities.DirectoryScanningTimerTask;
+import ch.systemsx.cisd.common.utilities.FileUtilities;
+import ch.systemsx.cisd.datamover.helper.FileSystemHelper;
+
+/**
+ * A {@link DirectoryScanningTimerTask.IPathHandler} that moves paths out of the way within one file system by calling
+ * {@link File#renameTo(File)}..
+ * 
+ * @author Bernd Rinn
+ */
+public class IntraFSPathMover implements DirectoryScanningTimerTask.IPathHandler
+{
+
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, IntraFSPathMover.class);
+
+    private static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY, IntraFSPathMover.class);
+
+    private final File destinationDirectory;
+
+    private final String prefixTemplate;
+
+    /**
+     * Creates a <var>PathMover</var>.
+     * 
+     * @param destinationDirectory The directory to move paths to.
+     */
+    public IntraFSPathMover(File destinationDirectory, String prefixTemplate)
+    {
+        assert destinationDirectory != null;
+        assert FileUtilities.checkDirectoryFullyAccessible(destinationDirectory, "destination") == null : FileUtilities
+                .checkDirectoryFullyAccessible(destinationDirectory, "destination");
+        assert prefixTemplate != null;
+
+        this.destinationDirectory = destinationDirectory;
+        this.prefixTemplate = prefixTemplate;
+    }
+
+    public boolean handle(File path)
+    {
+        assert path != null;
+        assert destinationDirectory != null;
+        assert prefixTemplate != null;
+
+        final String destinationPath =
+                FileSystemHelper.createDestinationPath(path, null, destinationDirectory, prefixTemplate);
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog
+                    .info(String.format("Moving path '%s' to '%s'", path.getPath(), destinationPath));
+        }
+        boolean movedOK = path.renameTo(new File(destinationPath));
+        if (movedOK == false)
+        {
+            notificationLog.error(String.format("Moving path '%s' to directory '%s' failed.", path,
+                    destinationDirectory));
+        }
+        return movedOK;
+    }
+
+}
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/MonitorStarter.java b/datamover/source/java/ch/systemsx/cisd/datamover/MonitorStarter.java
index e40683e81f9..7a74d203f11 100644
--- a/datamover/source/java/ch/systemsx/cisd/datamover/MonitorStarter.java
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/MonitorStarter.java
@@ -137,18 +137,13 @@ public class MonitorStarter
     private void recoverIncomingAfterShutdown(FileStore incomingStore, IReadPathOperations incomingReadOperations,
             boolean isIncomingRemote, LazyPathHandler localProcessor)
     {
-        if (isIncomingRemote == false)
-        {
-            return; // no recovery is needed
-        }
-
         recoverIncomingInProgress(incomingStore, incomingReadOperations, bufferDirs.getCopyInProgressDir(), bufferDirs
-                .getCopyCompleteDir());
+                .getCopyCompleteDir(), parameters.getPrefixForIncoming());
         recoverIncomingCopyComplete(bufferDirs.getCopyCompleteDir(), localProcessor);
     }
 
     private static void recoverIncomingInProgress(FileStore incomingStore, IReadPathOperations incomingReadOperations,
-            File copyInProgressDir, File copyCompleteDir)
+            File copyInProgressDir, File copyCompleteDir, String prefixTemplate)
     {
         final File[] files = FileSystemHelper.listFiles(copyInProgressDir);
         if (files == null || files.length == 0)
@@ -158,12 +153,12 @@ public class MonitorStarter
 
         for (File file : files)
         {
-            recoverIncomingAfterShutdown(file, incomingStore, incomingReadOperations, copyCompleteDir);
+            recoverIncomingAfterShutdown(file, incomingStore, incomingReadOperations, copyCompleteDir, prefixTemplate);
         }
     }
 
     private static void recoverIncomingAfterShutdown(File unfinishedFile, FileStore incomingStore,
-            IReadPathOperations incomingReadOperations, File copyCompleteDir)
+            IReadPathOperations incomingReadOperations, File copyCompleteDir, String prefixTemplate)
     {
         if (CopyFinishedMarker.isMarker(unfinishedFile))
         {
@@ -185,7 +180,7 @@ public class MonitorStarter
             if (markerFile.exists())
             {
                 // copy and marker exist - copy finished, but copied resource not moved
-                tryMoveFromInProgressToFinished(localCopy, markerFile, copyCompleteDir);
+                tryMoveFromInProgressToFinished(localCopy, markerFile, copyCompleteDir, prefixTemplate);
             } else
             // no marker
             {
@@ -197,7 +192,7 @@ public class MonitorStarter
                 } else
                 {
                     // move finished, but marker not created
-                    tryMoveFromInProgressToFinished(localCopy, null, copyCompleteDir);
+                    tryMoveFromInProgressToFinished(localCopy, null, copyCompleteDir, prefixTemplate);
                 }
             }
         }
@@ -238,7 +233,7 @@ public class MonitorStarter
 
     private boolean moveFromLocalIncoming(File source, LazyPathHandler localProcessor)
     {
-        final File finalFile = tryMoveLocal(source, bufferDirs.getCopyCompleteDir());
+        final File finalFile = tryMoveLocal(source, bufferDirs.getCopyCompleteDir(), parameters.getPrefixForIncoming());
         if (finalFile == null)
         {
             return false;
@@ -255,13 +250,16 @@ public class MonitorStarter
         {
             return false;
         }
+        FileSystemHelper.createDestinationPath(source, null, copyInProgressDir, parameters.getPrefixForIncoming());
         final File copiedFile = new File(copyInProgressDir, source.getName());
         assert copiedFile.exists();
         final File markerFile = CopyFinishedMarker.extractMarker(copiedFile);
         assert markerFile.exists();
 
         // 2. Move to final directory, delete marker
-        final File finalFile = tryMoveFromInProgressToFinished(copiedFile, markerFile, bufferDirs.getCopyCompleteDir());
+        final File finalFile =
+                tryMoveFromInProgressToFinished(copiedFile, markerFile, bufferDirs.getCopyCompleteDir(), parameters
+                        .getPrefixForIncoming());
         if (finalFile == null)
         {
             return false;
@@ -272,9 +270,10 @@ public class MonitorStarter
         return true;
     }
 
-    private static File tryMoveFromInProgressToFinished(File copiedFile, File markerFileOrNull, File copyCompleteDir)
+    private static File tryMoveFromInProgressToFinished(File copiedFile, File markerFileOrNull, File copyCompleteDir,
+            String prefixTemplate)
     {
-        final File finalFile = tryMoveLocal(copiedFile, copyCompleteDir);
+        final File finalFile = tryMoveLocal(copiedFile, copyCompleteDir, prefixTemplate);
         if (finalFile != null)
         {
             if (markerFileOrNull != null)
@@ -293,9 +292,9 @@ public class MonitorStarter
         return createRemotePathMover(sourceHostOrNull, localDestDir, null).handle(source);
     }
 
-    private static File tryMoveLocal(File sourceFile, File destinationDir)
+    private static File tryMoveLocal(File sourceFile, File destinationDir, String prefixTemplate)
     {
-        return FileSystemHelper.tryMoveLocal(sourceFile, destinationDir);
+        return FileSystemHelper.tryMoveLocal(sourceFile, destinationDir, prefixTemplate);
     }
 
     // --------------------------
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java b/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java
index 9b1b5a9bc08..c476e6d144b 100644
--- a/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/Parameters.java
@@ -232,6 +232,14 @@ public class Parameters implements ITimingParameters
             + "incoming paths needs manual intervention. ")
     private Pattern manualInterventionRegex = null;
 
+    /**
+     * A prefix for all incoming items. Note that '%t' will be replaced with the current timestamp in format
+     * 'yyyyMMddHHmmss'.
+     */
+    @Option(longName = "prefix-for-incoming", usage = "A string that all incoming items will be prepended with, "
+            + "'%t' will be replaced with the current time stamp.")
+    private String prefixForIncoming;
+
     /**
      * The command line parser.
      */
@@ -366,6 +374,7 @@ public class Parameters implements ITimingParameters
         treatIncomingAsRemote =
                 Boolean.parseBoolean(serviceProperties.getProperty("treat-incoming-as-remote", Boolean
                         .toString(DEFAULT_TREAT_INCOMING_AS_REMOTE)));
+        prefixForIncoming = serviceProperties.getProperty("prefix-for-incoming", "");
         if (serviceProperties.getProperty("incoming-dir") != null)
         {
             incomingDirectory = new File(serviceProperties.getProperty("incoming-dir"));
@@ -574,6 +583,15 @@ public class Parameters implements ITimingParameters
         return manualInterventionRegex;
     }
 
+    /**
+     * @return The prefix string to put in front of all incoming items. Note that '%t' will be replaced with the current
+     *         time stamp.
+     */
+    public String getPrefixForIncoming()
+    {
+        return prefixForIncoming;
+    }
+
     /**
      * Logs the current parameters to the {@link LogCategory#OPERATION} log.
      */
diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/helper/FileSystemHelper.java b/datamover/source/java/ch/systemsx/cisd/datamover/helper/FileSystemHelper.java
index 4f33ca6565e..cfcde8a366f 100644
--- a/datamover/source/java/ch/systemsx/cisd/datamover/helper/FileSystemHelper.java
+++ b/datamover/source/java/ch/systemsx/cisd/datamover/helper/FileSystemHelper.java
@@ -19,6 +19,8 @@ package ch.systemsx.cisd.datamover.helper;
 import java.io.File;
 import java.io.FileFilter;
 
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.time.DateFormatUtils;
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
 
@@ -28,7 +30,7 @@ import ch.systemsx.cisd.common.logging.Log4jSimpleLogger;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.utilities.FileUtilities;
-import ch.systemsx.cisd.common.utilities.IntraFSPathMover;
+import ch.systemsx.cisd.datamover.IntraFSPathMover;
 import ch.systemsx.cisd.datamover.LocalProcessorHandler;
 import ch.systemsx.cisd.datamover.intf.IReadPathOperations;
 
@@ -98,12 +100,56 @@ public class FileSystemHelper
             };
     }
 
-    /** moves source file to destination directory */
+    /**
+     * Moves source file to destination directory.
+     */
     public static File tryMoveLocal(File sourceFile, File destinationDir)
     {
-        boolean ok = new IntraFSPathMover(destinationDir).handle(sourceFile);
-        if (!ok)
+        return tryMoveLocal(sourceFile, destinationDir, "");
+    }
+
+    /**
+     * Moves source file to destination directory, putting <var>prefixTemplate</var> in front of its name after
+     * replacing '%t' with the current time stamp.
+     */
+    public static File tryMoveLocal(File sourceFile, File destinationDirectory, String prefixTemplate)
+    {
+        boolean ok = new IntraFSPathMover(destinationDirectory, prefixTemplate).handle(sourceFile);
+        if (ok == false)
+        {
             return null;
-        return new File(destinationDir, sourceFile.getName());
+        }
+        return new File(createDestinationPath(sourceFile, null, destinationDirectory, prefixTemplate));
     }
-}
+
+    /**
+     * Creates a destination path for copying <var>sourcePath</var> to <var>destinationDirectory</var> with prefix
+     * defined by <var>prefixTemplate</var>. Note that '%t' in <var>prefixTemplate</var> will be replaced by the
+     * current time stamp in format YYYYmmddhhMMss.
+     */
+    public static String createDestinationPath(File sourcePath, String destinationHostOrNull,
+            File destinationDirectory, String prefixTemplate)
+    {
+        assert sourcePath != null;
+        assert destinationDirectory != null;
+        assert prefixTemplate != null;
+
+        if (destinationHostOrNull != null)
+        {
+            return destinationHostOrNull + ":" + destinationDirectory.getPath() + File.separator
+                    + createPrefix(prefixTemplate) + sourcePath.getName();
+
+        } else
+        {
+            return destinationDirectory.getAbsolutePath() + File.separator + createPrefix(prefixTemplate)
+                    + sourcePath.getName();
+        }
+    }
+
+    private static String createPrefix(String prefixTemplate)
+    {
+        return StringUtils.replace(prefixTemplate, "%t", DateFormatUtils.format(System.currentTimeMillis(),
+                "yyyyMMddHHmmss"));
+    }
+
+}
\ No newline at end of file
-- 
GitLab