From 3921b2bb76585dbdcca3f790a70a51bc153b2e3b Mon Sep 17 00:00:00 2001
From: jakubs <jakubs>
Date: Mon, 21 May 2012 13:56:47 +0000
Subject: [PATCH] SP-45, BIS-21 move the recovery code from omniscient
 registrator to jython V2

SVN: 25318
---
 ...tOmniscientTopLevelDataSetRegistrator.java | 241 ++---------------
 .../DataSetStorageAlgorithmRunner.java        |   5 +
 .../DataSetStoragePrecommitRecoveryState.java |  12 +-
 .../DataSetStorageRecoveryManager.java        |   3 +-
 .../v2/JythonTopLevelDataSetHandlerV2.java    | 255 ++++++++++++++++++
 .../JythonDropboxRecoveryTest.java            |   2 +-
 6 files changed, 290 insertions(+), 228 deletions(-)

diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/AbstractOmniscientTopLevelDataSetRegistrator.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/AbstractOmniscientTopLevelDataSetRegistrator.java
index 3043c7526f8..8e910210b50 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/AbstractOmniscientTopLevelDataSetRegistrator.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/AbstractOmniscientTopLevelDataSetRegistrator.java
@@ -33,6 +33,7 @@ import org.apache.log4j.Logger;
 import ch.systemsx.cisd.base.exceptions.InterruptedExceptionUnchecked;
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.common.exceptions.NotImplementedException;
 import ch.systemsx.cisd.common.exceptions.Status;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.filesystem.FastRecursiveHardLinkMaker;
@@ -79,10 +80,10 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData;
 public abstract class AbstractOmniscientTopLevelDataSetRegistrator<T extends DataSetInformation>
         extends AbstractTopLevelDataSetRegistrator
 {
-    static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY,
+    protected static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY,
             AbstractOmniscientTopLevelDataSetRegistrator.class);
 
-    static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+    protected static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
             AbstractOmniscientTopLevelDataSetRegistrator.class);
 
     /**
@@ -248,7 +249,7 @@ public abstract class AbstractOmniscientTopLevelDataSetRegistrator<T extends Dat
 
     }
 
-    private final OmniscientTopLevelDataSetRegistratorState state;
+    protected final OmniscientTopLevelDataSetRegistratorState state;
 
     private boolean stopped;
 
@@ -305,8 +306,13 @@ public abstract class AbstractOmniscientTopLevelDataSetRegistrator<T extends Dat
 
     protected boolean hasRecoveryMarkerFile(File incoming)
     {
-        return getGlobalState().getStorageRecoveryManager().getProcessingMarkerFile(incoming)
-                .exists();
+        return false;
+    }
+
+    protected void handleRecovery(final File incomingFileOriginal)
+    {
+        throw new NotImplementedException(
+                "Recovery feature is not implemented for this kind of registrator");
     }
 
     /**
@@ -470,240 +476,25 @@ public abstract class AbstractOmniscientTopLevelDataSetRegistrator<T extends Dat
         return new RuntimeException(cause.toString());
     }
 
-    private void handleRecovery(final File incomingFileOriginal)
-    {
-        // get the marker file
-        final File recoveryMarkerFile =
-                state.getGlobalState().getStorageRecoveryManager()
-                        .getProcessingMarkerFile(incomingFileOriginal);
-
-        // deserialize recovery state
-        final DataSetStoragePrecommitRecoveryState<T> recoveryState =
-                state.getGlobalState().getStorageRecoveryManager()
-                        .extractPrecommittedCheckpoint(recoveryMarkerFile);
-
-        // then we should ensure that the recovery will actually take place itself!
-        final DataSetStorageRecoveryInfo recoveryInfo =
-                state.getGlobalState().getStorageRecoveryManager()
-                        .getRecoveryFileFromMarker(recoveryMarkerFile);
-
-        final File recoveryFile = recoveryInfo.getRecoveryStateFile();
-
-        if (false == recoveryFile.exists())
-        {
-            // TODO: is it safe to throw from here?
-            operationLog.error("recovery file does not exist. " + recoveryFile);
-            throw new IllegalStateException("Recovery file " + recoveryFile + " doesn't exist");
-        }
-
-        if (false == retryPeriodHasPassed(recoveryInfo))
-        {
-            operationLog.info("Found recovery inforation for "+incomingFileOriginal+". The recovery won't happen as the retry period has not yet passed" );
-            return;
-        }
-
-        operationLog.info("will recover from broken registration. Found marker file "
-                + recoveryMarkerFile + " and " + recoveryFile);
-
-        IDelegatedActionWithResult<Boolean> recoveryMarkerFileCleanupAction =
-                new IDelegatedActionWithResult<Boolean>()
-                    {
-                        public Boolean execute(boolean didOperationSucceed)
-                        {
-                            if (!didOperationSucceed
-                                    && recoveryInfo.getTryCount() >= state.getGlobalState()
-                                            .getStorageRecoveryManager().getMaximumRertyCount())
-                            {
-                                notificationLog.error("The dataset "
-                                        + recoveryState.getIncomingDataSetFile()
-                                                .getRealIncomingFile()
-                                        + " has failed to register. Giving up.");
-                                deleteMarkerFile(recoveryState);
-
-                                System.err.println("This is happening " + recoveryMarkerFile);
-                                File errorRecoveryMarkerFile =
-                                        new File(recoveryMarkerFile.getParent(),
-                                                recoveryMarkerFile.getName() + ".ERROR");
-                                state.fileOperations.move(recoveryMarkerFile,
-                                        errorRecoveryMarkerFile);
-                            } else
-                            {
-                                if (didOperationSucceed)
-                                {
-                                    deleteMarkerFile(recoveryState);
-
-                                    recoveryMarkerFile.delete();
-                                    recoveryFile.delete();
-                                } else
-                                {
-                                    // this replaces the recovery file with a new one with increased
-                                    // count
-                                    // FIXME: is this safe operation (how to assure, that it won't
-                                    // corrupt the recoveryMarkerFile?)
-
-                                    recoveryInfo.increaseTryCount();
-                                    recoveryInfo.setLastTry(new Date());
-                                    recoveryInfo.writeToFile(recoveryMarkerFile);
-                                }
-                            }
-                            return true;
-                        }
-
-                        private void deleteMarkerFile(
-                                final DataSetStoragePrecommitRecoveryState recoveryState)
-                        {
-                            File incomingMarkerFile =
-                                    MarkerFileUtility.getMarkerFileFromIncoming(recoveryState
-                                            .getIncomingDataSetFile().getRealIncomingFile());
-                            if (incomingMarkerFile.exists())
-                            {
-
-                                incomingMarkerFile.delete();
-                            }
-                        }
-                    };
-
-        PostRegistrationCleanUpAction cleanupAction =
-                new PostRegistrationCleanUpAction(recoveryState.getIncomingDataSetFile(),
-                        new DoNothingDelegatedAction());
-
-        handleRecoveryState(recoveryState, cleanupAction, recoveryMarkerFileCleanupAction);
-    }
-
     /**
-     * Check wheter the last retry + retry period < date.now
+     * Create an adaptor that offers access to the recovery hook functions.
      */
-    private boolean retryPeriodHasPassed(final DataSetStorageRecoveryInfo recoveryInfo)
+    protected IPrePostRegistrationHook<T> createRecoveryHookAdaptor()
     {
-        Calendar c = Calendar.getInstance();
-        c.setTime(recoveryInfo.getLastTry());
-        c.add(Calendar.SECOND, state.getGlobalState().getStorageRecoveryManager()
-                .getRetryPeriodInSeconds());
-        return c.getTime().before(new Date());
-    }
-
-    private void handleRecoveryState(DataSetStoragePrecommitRecoveryState<T> recoveryState,
-            final IDelegatedActionWithResult<Boolean> cleanAfterwardsAction,
-            final IDelegatedActionWithResult<Boolean> recoveryMarkerCleanup)
-    {
-        // TODO: Jobs left to do here:
-        // jython hooks
-
-        DssRegistrationLogger logger = recoveryState.getRegistrationLogger(state);
-
-        logger.log("The registration has been disturbed. Will try to recover...");
-
-        // rollback delegate
-        final List<Throwable> encounteredErrors = new ArrayList<Throwable>();
-
-        // keeps track of whether we should keep or delete the recovery files.
-        // we can delete if succesfully recovered, or rolledback, or gave up
-        boolean shouldDeleteRecoveryFiles = false;
-
-        IRollbackDelegate<T> rollbackDelegate = new IRollbackDelegate<T>()
-            {
-                public void didRollbackStorageAlgorithmRunner(
-                        DataSetStorageAlgorithmRunner<T> algorithm, Throwable ex,
-                        ErrorType errorType)
-                {
-                    encounteredErrors.add(ex);
-                }
-            };
-
-        // hookAdaptor
         final AbstractOmniscientTopLevelDataSetRegistrator<T> myself = this;
         IPrePostRegistrationHook<T> hookAdaptor = new IPrePostRegistrationHook<T>()
             {
                 public void executePreRegistration(DataSetRegistrationTransaction<T> transaction)
                 {
-                    // myself.didPreRegistration(null, transaction);
+                    myself.didPreRegistration(null, transaction);
                 }
 
                 public void executePostRegistration(DataSetRegistrationTransaction<T> transaction)
                 {
-                    // myself.didPostRegistration(null, transaction);
+                    myself.didPostRegistration(null, transaction);
                 }
             };
-
-        DataSetStorageAlgorithmRunner<T> runner =
-                new DataSetStorageAlgorithmRunner<T>(recoveryState.getIncomingDataSetFile(), // incoming
-                        recoveryState.getDataSetStorageAlgorithms(state), // algorithms
-                        rollbackDelegate, // rollback delegate,
-                        recoveryState.getRollbackStack(), // rollbackstack
-                        logger, // registrationLogger
-                        state.getGlobalState().getOpenBisService(), // openBisService
-                        hookAdaptor, // the hooks
-                        state.getGlobalState().getStorageRecoveryManager());
-        boolean registrationSuccessful = false;
-
-        operationLog.info("Recovery succesfully deserialized the state of the registration");
-        try
-        {
-            List<String> dataSetCodes = recoveryState.getDataSetCodes();
-            // TODO: we need to check for something more than just a registered datasets, for the
-            // registrations that doesn't register anything.
-            // OTOH: do we need to recover in this case? (as there is nothing to store)
-            // maybe then we should only checkpoint for recovery if there ARE datasets registered?
-
-            // TODO: verify why if this throws exception - the empty directory is created in a
-            // store?
-            List<ExternalData> registeredDataSets =
-                    state.getGlobalState().getOpenBisService().listDataSetsByCode(dataSetCodes);
-            if (registeredDataSets.isEmpty())
-            {
-                operationLog
-                        .info("Recovery hasn't found registration artifacts in the application server. Registration of metadata was not succesfull.");
-
-                IRollbackStackDelegate rollbackStackDelegate =
-                        new AbstractTransactionState.LiveTransactionRollbackDelegate(state
-                                .getGlobalState().getStagingDir());
-
-                recoveryState.getRollbackStack().setLockedState(false);
-
-                recoveryState.getRollbackStack().rollbackAll(rollbackStackDelegate);
-                UnstoreDataAction action =
-                        state.getOnErrorActionDecision().computeUndoAction(
-                                ErrorType.OPENBIS_REGISTRATION_FAILURE, null);
-                DataSetStorageRollbacker rollbacker =
-                        new DataSetStorageRollbacker(state, operationLog, action, recoveryState
-                                .getIncomingDataSetFile().getRealIncomingFile(), null, null,
-                                ErrorType.OPENBIS_REGISTRATION_FAILURE);
-                operationLog.info(rollbacker.getErrorMessageForLog());
-                rollbacker.doRollback(logger);
-
-                shouldDeleteRecoveryFiles = true;
-                //
-                // invokeRollbackTransactionFunction
-                //
-                // // rollback during metadata registration
-            } else
-            {
-                operationLog
-                        .info("Recovery has found datasets in the AS. The registration of metadata was succesfull.");
-                runner.storeAfterRegistration();
-                logger.registerSuccess();
-                registrationSuccessful = true;
-
-                shouldDeleteRecoveryFiles = true;
-            }
-        } catch (org.jmock.api.ExpectationError r)
-        {
-            // this exception can by only thrown by tests.
-            // propagation of the exception is essential to test some functionalities
-            throw r;
-        } catch (Throwable error)
-        {
-            System.err.println("Caught an error! " + error);
-            error.printStackTrace();
-            // in this case we should ignore, and run the recovery again after some time
-            encounteredErrors.add(error);
-        }
-
-        logger.logDssRegistrationResult(encounteredErrors);
-
-        cleanAfterwardsAction.execute(registrationSuccessful);
-
-        recoveryMarkerCleanup.execute(shouldDeleteRecoveryFiles);
+        return hookAdaptor;
     }
 
     /**
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithmRunner.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithmRunner.java
index 1d109cbd282..e48c1bb7a04 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithmRunner.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithmRunner.java
@@ -561,4 +561,9 @@ public class DataSetStorageAlgorithmRunner<T extends DataSetInformation>
     {
         return incomingDataSetFile;
     }
+    
+    public DataSetRegistrationContext getPersistentMap()
+    {
+        return transaction.getTransactionPersistentMap();
+    }
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStoragePrecommitRecoveryState.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStoragePrecommitRecoveryState.java
index ed69eda57bc..b4f5c95f6ca 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStoragePrecommitRecoveryState.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStoragePrecommitRecoveryState.java
@@ -43,9 +43,17 @@ public class DataSetStoragePrecommitRecoveryState<T extends DataSetInformation>
 
     private final DataSetFile incomingDataSetFile;
     
+    private final DataSetRegistrationContext persistentMap;
+    
+    public DataSetRegistrationContext getPersistentMap()
+    {
+        return persistentMap;
+    }
+
     public DataSetStoragePrecommitRecoveryState(
             List<DataSetStorageAlgorithm<T>> dataSetStorageAlgorithms,
-            DssRegistrationLogger logger, IRollbackStack rollbackStack, DataSetFile incomingDataSetFile)
+            DssRegistrationLogger logger, IRollbackStack rollbackStack, DataSetFile incomingDataSetFile,
+            DataSetRegistrationContext persistentMap)
     {
         this.dataSetRecoveryStorageAlgorithms =
                 new ArrayList<DataSetStoragePrecommitRecoveryAlgorithm<T>>();
@@ -57,6 +65,8 @@ public class DataSetStoragePrecommitRecoveryState<T extends DataSetInformation>
         this.rollbackStackBackingFiles = ((RollbackStack) rollbackStack).getBackingFiles();
         
         this.incomingDataSetFile = incomingDataSetFile;
+        
+        this.persistentMap = persistentMap;
     }
 
     public DataSetFile getIncomingDataSetFile()
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRecoveryManager.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRecoveryManager.java
index cc9e9f2c1b0..90d4e0f0aa0 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRecoveryManager.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRecoveryManager.java
@@ -58,7 +58,8 @@ public class DataSetStorageRecoveryManager implements IDataSetStorageRecoveryMan
 
         DataSetStoragePrecommitRecoveryState<T> recoveryState =
                 new DataSetStoragePrecommitRecoveryState<T>(runner.getDataSetStorageAlgorithms(),
-                        runner.getDssRegistrationLogger(), runner.getRollbackStack(), incoming);
+                        runner.getDssRegistrationLogger(), runner.getRollbackStack(), incoming,
+                        runner.getPersistentMap());
 
         runner.getRollbackStack().setLockedState(true);
 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java
index 93ab021dc42..844a7c53db3 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java
@@ -17,6 +17,10 @@
 package ch.systemsx.cisd.etlserver.registrator.api.v2;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
 
 import org.python.core.PyFunction;
 import org.python.util.PythonInterpreter;
@@ -24,11 +28,26 @@ import org.python.util.PythonInterpreter;
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.common.utilities.IDelegatedActionWithResult;
 import ch.systemsx.cisd.common.utilities.PythonUtils;
+import ch.systemsx.cisd.etlserver.DssRegistrationLogger;
 import ch.systemsx.cisd.etlserver.ITopLevelDataSetRegistratorDelegate;
 import ch.systemsx.cisd.etlserver.TopLevelDataSetRegistratorGlobalState;
+import ch.systemsx.cisd.etlserver.IStorageProcessorTransactional.UnstoreDataAction;
 import ch.systemsx.cisd.etlserver.registrator.DataSetFile;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationService;
+import ch.systemsx.cisd.etlserver.registrator.DataSetStorageAlgorithmRunner;
+import ch.systemsx.cisd.etlserver.registrator.DataSetStoragePrecommitRecoveryState;
+import ch.systemsx.cisd.etlserver.registrator.DataSetStorageRecoveryInfo;
+import ch.systemsx.cisd.etlserver.registrator.DataSetStorageRollbacker;
+import ch.systemsx.cisd.etlserver.registrator.MarkerFileUtility;
+import ch.systemsx.cisd.etlserver.registrator.AbstractOmniscientTopLevelDataSetRegistrator.DoNothingDelegatedAction;
+import ch.systemsx.cisd.etlserver.registrator.AbstractOmniscientTopLevelDataSetRegistrator.PostRegistrationCleanUpAction;
+import ch.systemsx.cisd.etlserver.registrator.DataSetStorageAlgorithmRunner.IPrePostRegistrationHook;
+import ch.systemsx.cisd.etlserver.registrator.DataSetStorageAlgorithmRunner.IRollbackDelegate;
+import ch.systemsx.cisd.etlserver.registrator.IDataSetOnErrorActionDecision.ErrorType;
+import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.AbstractTransactionState;
+import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.RollbackStack.IRollbackStackDelegate;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 
 /**
  * A top-level data set handler that runs a python (jython) script to register data sets.
@@ -127,4 +146,240 @@ public class JythonTopLevelDataSetHandlerV2<T extends DataSetInformation> extend
         // If there is a recovery marker file, do not add the file to faulty paths.
         return hasRecoveryMarkerFile(file);
     }
+    
+    @Override
+    protected boolean hasRecoveryMarkerFile(File incoming)
+    {
+        return getGlobalState().getStorageRecoveryManager().getProcessingMarkerFile(incoming)
+                .exists();
+    }
+    
+    @Override
+    protected void handleRecovery(final File incomingFileOriginal)
+    {
+        // get the marker file
+        final File recoveryMarkerFile =
+                state.getGlobalState().getStorageRecoveryManager()
+                        .getProcessingMarkerFile(incomingFileOriginal);
+
+        // deserialize recovery state
+        final DataSetStoragePrecommitRecoveryState<T> recoveryState =
+                state.getGlobalState().getStorageRecoveryManager()
+                        .extractPrecommittedCheckpoint(recoveryMarkerFile);
+
+        // then we should ensure that the recovery will actually take place itself!
+        final DataSetStorageRecoveryInfo recoveryInfo =
+                state.getGlobalState().getStorageRecoveryManager()
+                        .getRecoveryFileFromMarker(recoveryMarkerFile);
+
+        final File recoveryFile = recoveryInfo.getRecoveryStateFile();
+
+        if (false == recoveryFile.exists())
+        {
+            // TODO: is it safe to throw from here?
+            operationLog.error("recovery file does not exist. " + recoveryFile);
+            throw new IllegalStateException("Recovery file " + recoveryFile + " doesn't exist");
+        }
+
+        if (false == retryPeriodHasPassed(recoveryInfo))
+        {
+            operationLog.info("Found recovery inforation for " + incomingFileOriginal
+                    + ". The recovery won't happen as the retry period has not yet passed");
+            return;
+        }
+
+        operationLog.info("will recover from broken registration. Found marker file "
+                + recoveryMarkerFile + " and " + recoveryFile);
+
+        IDelegatedActionWithResult<Boolean> recoveryMarkerFileCleanupAction =
+                new IDelegatedActionWithResult<Boolean>()
+                    {
+                        public Boolean execute(boolean didOperationSucceed)
+                        {
+                            if (!didOperationSucceed
+                                    && recoveryInfo.getTryCount() >= state.getGlobalState()
+                                            .getStorageRecoveryManager().getMaximumRertyCount())
+                            {
+                                notificationLog.error("The dataset "
+                                        + recoveryState.getIncomingDataSetFile()
+                                                .getRealIncomingFile()
+                                        + " has failed to register. Giving up.");
+                                deleteMarkerFile();
+
+                                System.err.println("This is happening " + recoveryMarkerFile);
+                                File errorRecoveryMarkerFile =
+                                        new File(recoveryMarkerFile.getParent(),
+                                                recoveryMarkerFile.getName() + ".ERROR");
+                                state.getFileOperations().move(recoveryMarkerFile,
+                                        errorRecoveryMarkerFile);
+                            } else
+                            {
+                                if (didOperationSucceed)
+                                {
+                                    deleteMarkerFile();
+
+                                    recoveryMarkerFile.delete();
+                                    recoveryFile.delete();
+                                } else
+                                {
+                                    // this replaces the recovery file with a new one with increased
+                                    // count
+                                    // FIXME: is this safe operation (how to assure, that it won't
+                                    // corrupt the recoveryMarkerFile?)
+
+                                    recoveryInfo.increaseTryCount();
+                                    recoveryInfo.setLastTry(new Date());
+                                    recoveryInfo.writeToFile(recoveryMarkerFile);
+                                }
+                            }
+                            return true;
+                        }
+
+                        private void deleteMarkerFile()
+                        {
+                            File incomingMarkerFile =
+                                    MarkerFileUtility.getMarkerFileFromIncoming(recoveryState
+                                            .getIncomingDataSetFile().getRealIncomingFile());
+                            if (incomingMarkerFile.exists())
+                            {
+
+                                incomingMarkerFile.delete();
+                            }
+                        }
+                    };
+
+        PostRegistrationCleanUpAction cleanupAction =
+                new PostRegistrationCleanUpAction(recoveryState.getIncomingDataSetFile(),
+                        new DoNothingDelegatedAction());
+
+        handleRecoveryState(recoveryState, cleanupAction, recoveryMarkerFileCleanupAction);
+    }
+    
+    
+    /**
+     * Check wheter the last retry + retry period < date.now
+     */
+    private boolean retryPeriodHasPassed(final DataSetStorageRecoveryInfo recoveryInfo)
+    {
+        Calendar c = Calendar.getInstance();
+        c.setTime(recoveryInfo.getLastTry());
+        c.add(Calendar.SECOND, state.getGlobalState().getStorageRecoveryManager()
+                .getRetryPeriodInSeconds());
+        return c.getTime().before(new Date());
+    }
+
+    
+    private void handleRecoveryState(DataSetStoragePrecommitRecoveryState<T> recoveryState,
+            final IDelegatedActionWithResult<Boolean> cleanAfterwardsAction,
+            final IDelegatedActionWithResult<Boolean> recoveryMarkerCleanup)
+    {
+        // TODO: Jobs left to do here:
+        // jython hooks
+
+        DssRegistrationLogger logger = recoveryState.getRegistrationLogger(state);
+
+        logger.log("The registration has been disturbed. Will try to recover...");
+
+        // rollback delegate
+        final List<Throwable> encounteredErrors = new ArrayList<Throwable>();
+
+        // keeps track of whether we should keep or delete the recovery files.
+        // we can delete if succesfully recovered, or rolledback, or gave up
+        boolean shouldDeleteRecoveryFiles = false;
+
+        IRollbackDelegate<T> rollbackDelegate = new IRollbackDelegate<T>()
+            {
+                public void didRollbackStorageAlgorithmRunner(
+                        DataSetStorageAlgorithmRunner<T> algorithm, Throwable ex,
+                        ErrorType errorType)
+                {
+                    encounteredErrors.add(ex);
+                }
+            };
+
+        // hookAdaptor
+        IPrePostRegistrationHook<T> hookAdaptor = createRecoveryHookAdaptor();
+
+        DataSetStorageAlgorithmRunner<T> runner =
+                new DataSetStorageAlgorithmRunner<T>(recoveryState.getIncomingDataSetFile(), // incoming
+                        recoveryState.getDataSetStorageAlgorithms(state), // algorithms
+                        rollbackDelegate, // rollback delegate,
+                        recoveryState.getRollbackStack(), // rollbackstack
+                        logger, // registrationLogger
+                        state.getGlobalState().getOpenBisService(), // openBisService
+                        hookAdaptor, // the hooks
+                        state.getGlobalState().getStorageRecoveryManager());
+
+        boolean registrationSuccessful = false;
+
+        operationLog.info("Recovery succesfully deserialized the state of the registration");
+        try
+        {
+            List<String> dataSetCodes = recoveryState.getDataSetCodes();
+            // TODO: we need to check for something more than just a registered datasets, for the
+            // registrations that doesn't register anything.
+            // OTOH: do we need to recover in this case? (as there is nothing to store)
+            // maybe then we should only checkpoint for recovery if there ARE datasets registered?
+
+            // TODO: verify why if this throws exception - the empty directory is created in a
+            // store?
+            List<ExternalData> registeredDataSets =
+                    state.getGlobalState().getOpenBisService().listDataSetsByCode(dataSetCodes);
+            if (registeredDataSets.isEmpty())
+            {
+                operationLog
+                        .info("Recovery hasn't found registration artifacts in the application server. Registration of metadata was not succesfull.");
+
+                IRollbackStackDelegate rollbackStackDelegate =
+                        new AbstractTransactionState.LiveTransactionRollbackDelegate(state
+                                .getGlobalState().getStagingDir());
+
+                recoveryState.getRollbackStack().setLockedState(false);
+
+                recoveryState.getRollbackStack().rollbackAll(rollbackStackDelegate);
+                UnstoreDataAction action =
+                        state.getOnErrorActionDecision().computeUndoAction(
+                                ErrorType.OPENBIS_REGISTRATION_FAILURE, null);
+                DataSetStorageRollbacker rollbacker =
+                        new DataSetStorageRollbacker(state, operationLog, action, recoveryState
+                                .getIncomingDataSetFile().getRealIncomingFile(), null, null,
+                                ErrorType.OPENBIS_REGISTRATION_FAILURE);
+                operationLog.info(rollbacker.getErrorMessageForLog());
+                rollbacker.doRollback(logger);
+
+                shouldDeleteRecoveryFiles = true;
+                //
+                // invokeRollbackTransactionFunction
+                //
+                // // rollback during metadata registration
+            } else
+            {
+                operationLog
+                        .info("Recovery has found datasets in the AS. The registration of metadata was succesfull.");
+                runner.storeAfterRegistration();
+                logger.registerSuccess();
+                registrationSuccessful = true;
+
+                shouldDeleteRecoveryFiles = true;
+            }
+        } catch (org.jmock.api.ExpectationError r)
+        {
+            // this exception can by only thrown by tests.
+            // propagation of the exception is essential to test some functionalities
+            throw r;
+        } catch (Throwable error)
+        {
+            System.err.println("Caught an error! " + error);
+            error.printStackTrace();
+            // in this case we should ignore, and run the recovery again after some time
+            encounteredErrors.add(error);
+        }
+
+        logger.logDssRegistrationResult(encounteredErrors);
+
+        cleanAfterwardsAction.execute(registrationSuccessful);
+
+        recoveryMarkerCleanup.execute(shouldDeleteRecoveryFiles);
+    }
+
 }
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java
index 709559e1025..39c00bd9d7e 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java
@@ -82,7 +82,7 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest
         testCase.recoveryRertyCount = 3;
         testCases.add(testCase);
 
-        testCase = new RecoveryTestCase("check retry count incremented");
+        testCase = new RecoveryTestCase("check can't retry immediatelly after last failure");
         testCase.recoveryLastTry = new Date();
         testCase.nextTryInTheFuture = true;
         testCases.add(testCase);
-- 
GitLab