From 0b1a67ce43228d51193fd084f1750e70479db831 Mon Sep 17 00:00:00 2001
From: izabel <izabel>
Date: Tue, 23 Nov 2010 09:13:49 +0000
Subject: [PATCH] [LMS-1879] post registration script

SVN: 18855
---
 .../DataSetRegistrationAlgorithm.java         |  12 +-
 .../ch/systemsx/cisd/etlserver/ETLDaemon.java |  33 ++---
 .../etlserver/IPostRegistrationAction.java    |  26 ++++
 .../cisd/etlserver/ThreadParameters.java      |  27 ++++-
 .../etlserver/TransferredDataSetHandler.java  |  53 +++++---
 .../etlserver/api/v1/PutDataSetExecutor.java  |  12 +-
 .../utils/PostregistrationExecutor.java       | 113 ++++++++++++++++++
 .../TransferredDataSetHandlerTest.java        |  15 +--
 8 files changed, 244 insertions(+), 47 deletions(-)
 create mode 100644 datastore_server/source/java/ch/systemsx/cisd/etlserver/IPostRegistrationAction.java
 create mode 100644 datastore_server/source/java/ch/systemsx/cisd/etlserver/utils/PostregistrationExecutor.java

diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithm.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithm.java
index ebfaa3cb267..e1f78aebe11 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithm.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithm.java
@@ -83,9 +83,13 @@ public abstract class DataSetRegistrationAlgorithm
 
     protected String errorMessageTemplate;
 
+    private IPostRegistrationAction postRegistrationAction;
+
     public DataSetRegistrationAlgorithm(File incomingDataSetFile,
-            IDelegatedActionWithResult<Boolean> cleanAftrewardsAction)
+            IDelegatedActionWithResult<Boolean> cleanAftrewardsAction,
+            IPostRegistrationAction postRegistrationAction)
     {
+        this.postRegistrationAction = postRegistrationAction;
         this.errorMessageTemplate = DataSetRegistrationAlgorithm.DATA_SET_STORAGE_FAILURE_TEMPLATE;
         this.incomingDataSetFile = incomingDataSetFile;
         this.cleanAftrewardsAction = cleanAftrewardsAction;
@@ -225,9 +229,10 @@ public abstract class DataSetRegistrationAlgorithm
             }
             assert dataFile != null : "The folder that contains the stored data should not be null.";
             final String relativePath = FileUtilities.getRelativeFile(storeRoot, dataFile);
+            String absolutePath = dataFile.getAbsolutePath();
             assert relativePath != null : String.format(
-                    TransferredDataSetHandler.TARGET_NOT_RELATIVE_TO_STORE_ROOT,
-                    dataFile.getAbsolutePath(), storeRoot.getAbsolutePath());
+                    TransferredDataSetHandler.TARGET_NOT_RELATIVE_TO_STORE_ROOT, absolutePath,
+                    storeRoot.getAbsolutePath());
             final StorageFormat availableFormat = getStorageProcessor().getStorageFormat();
             final BooleanOrUnknown isCompleteFlag = dataSetInformation.getIsCompleteFlag();
             // Ensure that we either register the data set and initiate the processing copy or
@@ -238,6 +243,7 @@ public abstract class DataSetRegistrationAlgorithm
                 errorMessageTemplate =
                         DataSetRegistrationAlgorithm.DATA_SET_REGISTRATION_FAILURE_TEMPLATE;
                 plainRegisterDataSet(data, relativePath, availableFormat, isCompleteFlag);
+                postRegistrationAction.execute(data.getCode(), absolutePath);
                 clean();
             } finally
             {
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/ETLDaemon.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/ETLDaemon.java
index 85f91b8bd19..85acbdbdc2e 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/ETLDaemon.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/ETLDaemon.java
@@ -38,6 +38,7 @@ import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 import ch.systemsx.cisd.common.exceptions.HighLevelException;
 import ch.systemsx.cisd.common.exceptions.Status;
 import ch.systemsx.cisd.common.filesystem.DirectoryScanningTimerTask;
+import ch.systemsx.cisd.common.filesystem.DirectoryScanningTimerTask.IScannedStore;
 import ch.systemsx.cisd.common.filesystem.FaultyPathDirectoryScanningHandler;
 import ch.systemsx.cisd.common.filesystem.FileUtilities;
 import ch.systemsx.cisd.common.filesystem.IDirectoryScanningHandler;
@@ -46,7 +47,6 @@ import ch.systemsx.cisd.common.filesystem.LastModificationChecker;
 import ch.systemsx.cisd.common.filesystem.QueueingPathRemoverService;
 import ch.systemsx.cisd.common.filesystem.QuietPeriodFileFilter;
 import ch.systemsx.cisd.common.filesystem.StoreItem;
-import ch.systemsx.cisd.common.filesystem.DirectoryScanningTimerTask.IScannedStore;
 import ch.systemsx.cisd.common.highwatermark.HighwaterMarkDirectoryScanningHandler;
 import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher;
 import ch.systemsx.cisd.common.highwatermark.HostAwareFileWithHighwaterMark;
@@ -84,11 +84,11 @@ public final class ETLDaemon
 
     static final String NOTIFY_SUCCESSFUL_REGISTRATION = "notify-successful-registration";
 
-    private static final Logger operationLog =
-            LogFactory.getLogger(LogCategory.OPERATION, ETLDaemon.class);
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            ETLDaemon.class);
 
-    private static final Logger notificationLog =
-            LogFactory.getLogger(LogCategory.NOTIFY, ETLDaemon.class);
+    private static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY,
+            ETLDaemon.class);
 
     @Private
     static IExitHandler exitHandler = SystemExit.SYSTEM_EXIT;
@@ -170,8 +170,8 @@ public final class ETLDaemon
                         + "available at at later time, we keep the server running anyway.", e);
             } else
             {
-                System.err.printf(msgStart + " [%s: %s]\n", e.getClass().getSimpleName(), e
-                        .getMessage());
+                System.err.printf(msgStart + " [%s: %s]\n", e.getClass().getSimpleName(),
+                        e.getMessage());
                 exitHandler.exit(1);
             }
         } catch (final RuntimeException e)
@@ -309,9 +309,11 @@ public final class ETLDaemon
         plugin.getStorageProcessor().setStoreRootDirectory(storeRootDir);
         String dssCode = DssPropertyParametersUtil.getDataStoreCode(properties);
         boolean deleteUnidentified = threadParameters.deleteUnidentified();
+
         return new TransferredDataSetHandler(dssCode, plugin, openBISService, mailClient,
-                dataSetValidator, notifySuccessfulRegistration, threadParameters
-                        .useIsFinishedMarkerFile(), deleteUnidentified);
+                dataSetValidator, notifySuccessfulRegistration,
+                threadParameters.useIsFinishedMarkerFile(), deleteUnidentified,
+                threadParameters.tryGetPostRegistrationScript());
     }
 
     private static FileFilter createFileFilter(File incomingDataDirectory,
@@ -333,14 +335,14 @@ public final class ETLDaemon
         LastModificationChecker lastModificationChecker =
                 new LastModificationChecker(incomingDataDirectory);
         final IStoreItemFilter quietPeriodFilter =
-                new QuietPeriodFileFilter(lastModificationChecker, parameters
-                        .getQuietPeriodMillis(), ignoredErrorCountBeforeNotification);
+                new QuietPeriodFileFilter(lastModificationChecker,
+                        parameters.getQuietPeriodMillis(), ignoredErrorCountBeforeNotification);
         return new FileFilter()
             {
                 public boolean accept(File pathname)
                 {
-                    assert pathname.getParentFile().getAbsolutePath().equals(
-                            incomingDataDirectory.getAbsolutePath()) : "The file should come to the filter only from the incoming directory";
+                    assert pathname.getParentFile().getAbsolutePath()
+                            .equals(incomingDataDirectory.getAbsolutePath()) : "The file should come to the filter only from the incoming directory";
 
                     StoreItem storeItem = new StoreItem(pathname.getName());
                     return quietPeriodFilter.accept(storeItem);
@@ -367,8 +369,9 @@ public final class ETLDaemon
                                 mover.getRegistrationLock().tryLock(timeoutMillis,
                                         TimeUnit.MILLISECONDS);
                         final long timeoutLeftMillis =
-                                Math.max(timeoutMillis / 2, timeoutMillis
-                                        - (System.currentTimeMillis() - startTimeMillis));
+                                Math.max(timeoutMillis / 2,
+                                        timeoutMillis
+                                                - (System.currentTimeMillis() - startTimeMillis));
                         if (lockOK == false)
                         {
                             operationLog.error("Failed to get lock for shutdown of thread '"
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/IPostRegistrationAction.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/IPostRegistrationAction.java
new file mode 100644
index 00000000000..564695f1662
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/IPostRegistrationAction.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010 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.etlserver;
+
+/**
+ * @author Izabela Adamczyk
+ */
+public interface IPostRegistrationAction
+{
+    boolean execute(String dataSetCode, String dataSetAbsolutePathInStore);
+
+}
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/ThreadParameters.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/ThreadParameters.java
index 089498d9d51..5d03ab456ea 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/ThreadParameters.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/ThreadParameters.java
@@ -38,6 +38,15 @@ import ch.systemsx.cisd.common.utilities.PropertyUtils;
  */
 public final class ThreadParameters
 {
+
+    /**
+     * A path to a script which should be called from command line after successful data set
+     * registration. The script gets two parameters: data set code and absolute path to the data set
+     * in the data store.
+     */
+    @Private
+    static final String POSTREFGISTRATION_SCRIPT_KEY = "postregistration-script";
+
     @Private
     static final String GROUP_CODE_KEY = "group-code";
 
@@ -51,8 +60,8 @@ public final class ThreadParameters
     @Private
     static final String INCOMING_DATA_COMPLETENESS_CONDITION_AUTODETECTION = "auto-detection";
 
-    private static final Logger operationLog =
-            LogFactory.getLogger(LogCategory.OPERATION, ThreadParameters.class);
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            ThreadParameters.class);
 
     private static final String INCOMING_DIR = "incoming-dir";
 
@@ -72,6 +81,8 @@ public final class ThreadParameters
 
     private final String groupCode;
 
+    private final String postRegistrationScript;
+
     private final boolean useIsFinishedMarkerFile;
 
     private final boolean deleteUnidentified;
@@ -87,6 +98,7 @@ public final class ThreadParameters
         this.incomingDataDirectory = extractIncomingDataDir(threadProperties);
         this.plugin = new PropertiesBasedETLServerPlugin(threadProperties);
         this.groupCode = tryGetGroupCode(threadProperties);
+        this.postRegistrationScript = tryGetPostRegistartionScript(threadProperties);
         String completenessCondition =
                 PropertyUtils.getProperty(threadProperties, INCOMING_DATA_COMPLETENESS_CONDITION,
                         INCOMING_DATA_COMPLETENESS_CONDITION_MARKER_FILE);
@@ -150,6 +162,12 @@ public final class ThreadParameters
         return nullIfEmpty(PropertyUtils.getProperty(properties, GROUP_CODE_KEY));
     }
 
+    @Private
+    static final String tryGetPostRegistartionScript(final Properties properties)
+    {
+        return nullIfEmpty(PropertyUtils.getProperty(properties, POSTREFGISTRATION_SCRIPT_KEY));
+    }
+
     private static String nullIfEmpty(String value)
     {
         return StringUtils.defaultIfEmpty(value, null);
@@ -163,6 +181,11 @@ public final class ThreadParameters
         return groupCode;
     }
 
+    public final String tryGetPostRegistrationScript()
+    {
+        return postRegistrationScript;
+    }
+
     public boolean useIsFinishedMarkerFile()
     {
         return useIsFinishedMarkerFile;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java
index f5e678f3922..2826b9fc3a1 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java
@@ -40,6 +40,7 @@ import ch.systemsx.cisd.common.mail.IMailClient;
 import ch.systemsx.cisd.common.utilities.IDelegatedActionWithResult;
 import ch.systemsx.cisd.common.utilities.ISelfTestable;
 import ch.systemsx.cisd.etlserver.IStorageProcessor.UnstoreDataAction;
+import ch.systemsx.cisd.etlserver.utils.PostregistrationExecutor;
 import ch.systemsx.cisd.etlserver.validation.IDataSetValidator;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
@@ -57,14 +58,14 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
     static final String TARGET_NOT_RELATIVE_TO_STORE_ROOT =
             "Target path '%s' is not relative to store root directory '%s'.";
 
-    static final Logger notificationLog =
-            LogFactory.getLogger(LogCategory.NOTIFY, TransferredDataSetHandler.class);
+    static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY,
+            TransferredDataSetHandler.class);
 
-    static final Logger operationLog =
-            LogFactory.getLogger(LogCategory.OPERATION, TransferredDataSetHandler.class);
+    static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            TransferredDataSetHandler.class);
 
-    static final NamedDataStrategy ERROR_DATA_STRATEGY =
-            new NamedDataStrategy(DataStoreStrategyKey.ERROR);
+    static final NamedDataStrategy ERROR_DATA_STRATEGY = new NamedDataStrategy(
+            DataStoreStrategyKey.ERROR);
 
     private final IStoreRootDirectoryHolder storeRootDirectoryHolder;
 
@@ -100,6 +101,8 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
 
     private final IDataSetValidator dataSetValidator;
 
+    private final IPostRegistrationAction postRegistrationAction;
+
     /**
      * @param dataSetValidator
      * @param useIsFinishedMarkerFile if true, file/directory is processed when a marker file for it
@@ -109,12 +112,13 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
     public TransferredDataSetHandler(String dssCode, final IETLServerPlugin plugin,
             final IEncapsulatedOpenBISService limsService, final IMailClient mailClient,
             IDataSetValidator dataSetValidator, final boolean notifySuccessfulRegistration,
-            boolean useIsFinishedMarkerFile, boolean deleteUnidentified)
+            boolean useIsFinishedMarkerFile, boolean deleteUnidentified,
+            String postRegistrationScriptOrNull)
 
     {
         this(dssCode, plugin.getStorageProcessor(), plugin, limsService, mailClient,
                 dataSetValidator, notifySuccessfulRegistration, useIsFinishedMarkerFile,
-                deleteUnidentified);
+                deleteUnidentified, postRegistrationScriptOrNull);
     }
 
     TransferredDataSetHandler(String dssCode,
@@ -122,7 +126,7 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
             final IETLServerPlugin plugin, final IEncapsulatedOpenBISService limsService,
             final IMailClient mailClient, IDataSetValidator dataSetValidator,
             final boolean notifySuccessfulRegistration, boolean useIsFinishedMarkerFile,
-            boolean deleteUnidentified)
+            boolean deleteUnidentified, String postRegistrationScriptOrNull)
 
     {
         assert dssCode != null : "Unspecified data store code";
@@ -146,6 +150,7 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
         this.fileOperations = FileOperations.getMonitoredInstanceForCurrentThread();
         this.useIsFinishedMarkerFile = useIsFinishedMarkerFile;
         this.deleteUnidentified = deleteUnidentified;
+        this.postRegistrationAction = PostregistrationExecutor.create(postRegistrationScriptOrNull);
     }
 
     /**
@@ -208,8 +213,8 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
             if (fileOperations.exists(storeRootDirectory) == false)
             {
                 throw EnvironmentFailureException.fromTemplate(
-                        "Store root directory '%s' does not exist.", storeRootDirectory
-                                .getAbsolutePath());
+                        "Store root directory '%s' does not exist.",
+                        storeRootDirectory.getAbsolutePath());
             } else
             {
                 throw new ConfigurationFailureException(errorMessage);
@@ -263,7 +268,13 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
                             return deleteAndLogIsFinishedMarkerFile(isFinishedFile);
                         }
                     };
-        return new RegistrationHelper(this, incomingDataSetFile, cleanAftrewardsAction);
+        return new RegistrationHelper(this, incomingDataSetFile, cleanAftrewardsAction,
+                createPostRegistrationAction());
+    }
+
+    private IPostRegistrationAction createPostRegistrationAction()
+    {
+        return postRegistrationAction;
     }
 
     private DataSetRegistrationAlgorithm createRegistrationHelperWithQuietPeriodFilter(
@@ -277,7 +288,8 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
                             return true; // do nothing
                         }
                     };
-        return new RegistrationHelper(this, incomingDataSetFile, cleanAftrewardsAction);
+        return new RegistrationHelper(this, incomingDataSetFile, cleanAftrewardsAction,
+                createPostRegistrationAction());
     }
 
     /**
@@ -303,8 +315,8 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
             fileOperations.delete(isFinishedPath);
             throw EnvironmentFailureException.fromTemplate(String.format(
                     "Error moving path '%s' from '%s' to '%s': %s", incomingDataSetPath.getName(),
-                    incomingDataSetPath.getParent(), storeRootDirectoryHolder
-                            .getStoreRootDirectory(), errorMsg));
+                    incomingDataSetPath.getParent(),
+                    storeRootDirectoryHolder.getStoreRootDirectory(), errorMsg));
         }
         return incomingDataSetPath;
     }
@@ -337,11 +349,14 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
          * @param transferredDataSetHandler
          * @param incomingDataSetFile
          * @param cleanAftrewardsAction
+         * @param postRegistrationAction
          */
         RegistrationHelper(TransferredDataSetHandler transferredDataSetHandler,
-                File incomingDataSetFile, IDelegatedActionWithResult<Boolean> cleanAftrewardsAction)
+                File incomingDataSetFile,
+                IDelegatedActionWithResult<Boolean> cleanAftrewardsAction,
+                IPostRegistrationAction postRegistrationAction)
         {
-            super(incomingDataSetFile, cleanAftrewardsAction);
+            super(incomingDataSetFile, cleanAftrewardsAction, postRegistrationAction);
         }
 
         // state accessors
@@ -475,8 +490,8 @@ public final class TransferredDataSetHandler implements IPathHandler, ISelfTesta
                             new BaseDirectoryHolder(TransferredDataSetHandler.ERROR_DATA_STRATEGY,
                                     baseDirectory, incomingDataSetFile);
                     boolean moveInCaseOfErrorOk =
-                            FileRenamer.renameAndLog(incomingDataSetFile, baseDirectoryHolder
-                                    .getTargetFile());
+                            FileRenamer.renameAndLog(incomingDataSetFile,
+                                    baseDirectoryHolder.getTargetFile());
                     writeThrowable(throwable);
                     if (moveInCaseOfErrorOk)
                     {
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java
index abafc55f983..1ae1d3a1c06 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java
@@ -48,6 +48,7 @@ import ch.systemsx.cisd.etlserver.IDataSetHandlerRpc;
 import ch.systemsx.cisd.etlserver.IDataSetInfoExtractor;
 import ch.systemsx.cisd.etlserver.IDataStrategyStore;
 import ch.systemsx.cisd.etlserver.IETLServerPlugin;
+import ch.systemsx.cisd.etlserver.IPostRegistrationAction;
 import ch.systemsx.cisd.etlserver.IStorageProcessor;
 import ch.systemsx.cisd.etlserver.ITypeExtractor;
 import ch.systemsx.cisd.etlserver.validation.IDataSetValidator;
@@ -402,6 +403,15 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
         return overridingTypeExtractor;
     }
 
+    private static class PostRegistrationAction implements IPostRegistrationAction
+    {
+
+        public boolean execute(String dataSetCode, String dataSetAbsolutePathInStore)
+        {
+            return true;// do nothing
+        }
+    }
+
     private static class CleanAfterwardsAction implements IDelegatedActionWithResult<Boolean>
     {
         public Boolean execute()
@@ -472,7 +482,7 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
         public RegistrationHelper(PutDataSetService service, IETLServerPlugin plugin,
                 File incomingDataSetFile)
         {
-            super(incomingDataSetFile, new CleanAfterwardsAction());
+            super(incomingDataSetFile, new CleanAfterwardsAction(), new PostRegistrationAction());
         }
 
         @Override
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/utils/PostregistrationExecutor.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/utils/PostregistrationExecutor.java
new file mode 100644
index 00000000000..330943d0002
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/utils/PostregistrationExecutor.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2009 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.etlserver.utils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.common.concurrent.ConcurrencyUtilities;
+import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
+import ch.systemsx.cisd.common.filesystem.FileOperations;
+import ch.systemsx.cisd.common.filesystem.IFileOperations;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.process.ProcessExecutionHelper;
+import ch.systemsx.cisd.common.shared.basic.utils.StringUtils;
+import ch.systemsx.cisd.etlserver.IPostRegistrationAction;
+
+/**
+ * A class which is configured from properties and is able to execute a script from the command line
+ * using the configured path.
+ * 
+ * @author Izabela Adamczyk
+ */
+public class PostregistrationExecutor implements IPostRegistrationAction
+{
+
+    private final static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            PostregistrationExecutor.class);
+
+    private final static Logger machineLog = LogFactory.getLogger(LogCategory.MACHINE,
+            PostregistrationExecutor.class);
+
+    static class EmptyScriptExecutor implements IPostRegistrationAction
+    {
+
+        public boolean execute(String dataSetCode, String dataSetAbsolutePathInStore)
+        {
+            return true;
+        }
+    }
+
+    public static IPostRegistrationAction create(String scriptPath)
+    {
+        if (scriptPath != null)
+        {
+            return new PostregistrationExecutor(scriptPath);
+        } else
+        {
+            operationLog.debug("No postregistration script found, skipping execution.");
+            return new EmptyScriptExecutor();
+        }
+    }
+
+    private final String scriptPath;
+
+    private PostregistrationExecutor(String script)
+    {
+        this.scriptPath = script;
+        File file = new File(script);
+        IFileOperations fileOperations = FileOperations.getInstance();
+        if (fileOperations.isFile(file) == false || fileOperations.canRead(file) == false)
+        {
+            throw new ConfigurationFailureException(String.format(
+                    "Cannot access postregistration script '%s'.", script));
+        }
+        operationLog.info("Postregistration script: " + script);
+    }
+
+    public boolean execute(final String dataSetCode, final String dataSetAbsolutePathInStore)
+    {
+        return callScript(scriptPath, dataSetCode, dataSetAbsolutePathInStore);
+    }
+
+    private static boolean callScript(String scriptPath, String... args)
+    {
+        List<String> cmd = new ArrayList<String>();
+        cmd.add(scriptPath);
+        cmd.addAll(Arrays.asList(args));
+        boolean result =
+                ProcessExecutionHelper.runAndLog(cmd, operationLog, machineLog,
+                        ConcurrencyUtilities.NO_TIMEOUT);
+        if (result == false)
+        {
+            operationLog.warn(String.format("Script execution failed: SCRIPT(%s) PARAMETERS(%s)",
+                    scriptPath, StringUtils.join(args, ",")));
+        } else
+        {
+            operationLog.debug(String.format(
+                    "Successful script execution: SCRIPT(%s) PARAMETERS(%s)", scriptPath,
+                    StringUtils.join(args, ",")));
+        }
+        return result;
+    }
+
+}
\ No newline at end of file
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandlerTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandlerTest.java
index 380d5b19b18..588e96c0414 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandlerTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandlerTest.java
@@ -263,7 +263,8 @@ public final class TransferredDataSetHandlerTest extends AbstractFileSystemTestC
         dataSetValidator = context.mock(IDataSetValidator.class);
         handler =
                 new TransferredDataSetHandler("dss", storageProcessor, plugin,
-                        authorizedLimsService, mailClient, dataSetValidator, true, true, false);
+                        authorizedLimsService, mailClient, dataSetValidator, true, true, false,
+                        null);
 
         dataSetInformation = new DataSetInformation();
         dataSetInformation.setDataSetType(DATA_SET_TYPE);
@@ -307,8 +308,8 @@ public final class TransferredDataSetHandlerTest extends AbstractFileSystemTestC
 
     private final String normalize(final String message)
     {
-        return message.replace(workingDirectory.getAbsolutePath(), "/<wd>").replace(
-                workingDirectory.getPath(), "<wd>").replace('\\', '/');
+        return message.replace(workingDirectory.getAbsolutePath(), "/<wd>")
+                .replace(workingDirectory.getPath(), "<wd>").replace('\\', '/');
     }
 
     private final NewExternalData createTargetData(final File dataSet)
@@ -631,8 +632,8 @@ public final class TransferredDataSetHandlerTest extends AbstractFileSystemTestC
         assert data1.exists() && data2.exists();
         prepareForStrategy(data1, null);
         final File toDir =
-                new File(new File(workingDirectory, NamedDataStrategy
-                        .getDirectoryName(DataStoreStrategyKey.UNIDENTIFIED)),
+                new File(new File(workingDirectory,
+                        NamedDataStrategy.getDirectoryName(DataStoreStrategyKey.UNIDENTIFIED)),
                         IdentifiedDataStrategy.createDataSetTypeDirectory(DATA_SET_TYPE));
 
         final LogMonitoringAppender appender =
@@ -699,8 +700,8 @@ public final class TransferredDataSetHandlerTest extends AbstractFileSystemTestC
                 new File(workingDirectory, NamedDataStrategy.getDirectoryName(key));
         assertEquals(true, strategyDirectory.exists());
         final File dataSetTypeDir =
-                new File(strategyDirectory, IdentifiedDataStrategy
-                        .createDataSetTypeDirectory(DATA_SET_TYPE));
+                new File(strategyDirectory,
+                        IdentifiedDataStrategy.createDataSetTypeDirectory(DATA_SET_TYPE));
         assertEquals(true, dataSetTypeDir.exists());
         final File targetFile = new File(dataSetTypeDir, dataSet.getName());
         assertEquals(true, targetFile.exists());
-- 
GitLab