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 9ad70f4b99a20d21594d4e2a3da0f2e1e574b7ef..d51c91f3a817f02a793a4e16b193cf417565a799 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithm.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithm.java @@ -120,7 +120,7 @@ public class DataSetRegistrationAlgorithm public DataSetRegistrationAlgorithmState(File incomingDataSetFile, IEncapsulatedOpenBISService openBisService, - IDelegatedActionWithResult<Boolean> cleanAftrewardsAction, + IDelegatedActionWithResult<Boolean> cleanAfterwardsAction, IPreRegistrationAction preRegistrationAction, IPostRegistrationAction postRegistrationAction, DataSetInformation dataSetInformation, IDataStoreStrategy dataStoreStrategy, @@ -131,7 +131,7 @@ public class DataSetRegistrationAlgorithm { this.incomingDataSetFile = incomingDataSetFile; this.openBisService = openBisService; - this.cleanAfterwardsAction = cleanAftrewardsAction; + this.cleanAfterwardsAction = cleanAfterwardsAction; this.preRegistrationAction = preRegistrationAction; this.postRegistrationAction = postRegistrationAction; this.dataSetInformation = dataSetInformation; @@ -204,7 +204,8 @@ public class DataSetRegistrationAlgorithm } public DataSetRegistrationAlgorithm(DataSetRegistrationAlgorithmState state, - IRollbackDelegate rollbackDelegate, IDataSetInApplicationServerRegistrator applicationServerRegistrator) + IRollbackDelegate rollbackDelegate, + IDataSetInApplicationServerRegistrator applicationServerRegistrator) { this.state = state; this.rollbackDelegate = rollbackDelegate; @@ -352,7 +353,8 @@ public class DataSetRegistrationAlgorithm return state.cleanAfterwardsAction.execute(); } - private static class DefaultApplicationServerRegistrator implements IDataSetInApplicationServerRegistrator + private static class DefaultApplicationServerRegistrator implements + IDataSetInApplicationServerRegistrator { private final IEncapsulatedOpenBISService openBisService; @@ -629,4 +631,9 @@ public class DataSetRegistrationAlgorithm { return operationLog; } + + public File getIncomingDataSetFile() + { + return state.incomingDataSetFile; + } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationHelper.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationHelper.java index 89bff7aa93e128479b04ac3c67ffcec3a769b28e..4d3c71b09431d9671ae59b0840e3484ea65df772 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationHelper.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationHelper.java @@ -17,13 +17,9 @@ package ch.systemsx.cisd.etlserver; import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; import java.util.List; import java.util.concurrent.locks.Lock; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -86,7 +82,8 @@ public abstract class DataSetRegistrationHelper implements public DataSetRegistrationHelper(File incomingDataSetFile, IDelegatedActionWithResult<Boolean> cleanAftrewardsAction, IPreRegistrationAction preRegistrationAction, - IPostRegistrationAction postRegistrationAction, IDataSetInApplicationServerRegistrator appServerRegistrator) + IPostRegistrationAction postRegistrationAction, + IDataSetInApplicationServerRegistrator appServerRegistrator) { DataSetInformation dataSetInformation = extractDataSetInformation(incomingDataSetFile); IDataStoreStrategy dataStoreStrategy = @@ -188,28 +185,6 @@ public abstract class DataSetRegistrationHelper implements } } - protected final void writeThrowable(final Throwable throwable) - { - final String fileName = incomingDataSetFile.getName() + ".exception"; - final File file = - new File(registrationAlgorithm.getBaseDirectoryHolder().getTargetFile() - .getParentFile(), fileName); - FileWriter writer = null; - try - { - writer = new FileWriter(file); - throwable.printStackTrace(new PrintWriter(writer)); - } catch (final IOException e) - { - TransferredDataSetHandler.operationLog.warn(String.format( - "Could not write out the exception '%s' in file '%s'.", fileName, - file.getAbsolutePath()), e); - } finally - { - IOUtils.closeQuietly(writer); - } - } - public void rollback(DataSetRegistrationAlgorithm algo, Throwable ex) { rollback(ex); diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationRollbacker.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationRollbacker.java new file mode 100644 index 0000000000000000000000000000000000000000..7e80abcbf93eaf8f53f072dda634b141f64ac280 --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataSetRegistrationRollbacker.java @@ -0,0 +1,143 @@ +/* + * Copyright 2011 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; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; + +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; + +import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.logging.Log4jSimpleLogger; +import ch.systemsx.cisd.etlserver.IStorageProcessor.UnstoreDataAction; + +/** + * Utility class that rollsback a data set registration. + * + * @author Chandrasekhar Ramakrishnan + */ +public class DataSetRegistrationRollbacker +{ + private final boolean stopped; + + private final DataSetRegistrationAlgorithm registrationAlgorithm; + + private final File incomingDataSetFile; + + private final Logger notificationLog; + + private final Logger operationLog; + + private final Throwable throwable; + + public DataSetRegistrationRollbacker(boolean stopped, + DataSetRegistrationAlgorithm registrationAlgorithm, File incomingDataSetFile, + Logger notificationLog, Logger operationLog, Throwable throwable) + { + this.stopped = stopped; + this.registrationAlgorithm = registrationAlgorithm; + this.incomingDataSetFile = incomingDataSetFile; + this.notificationLog = notificationLog; + this.operationLog = operationLog; + this.throwable = throwable; + } + + public void doRollback() throws Error + { + if (stopped) + { + Thread.interrupted(); // Ensure the thread's interrupted state is cleared. + getOperationLog().warn( + String.format("Requested to stop registration of data set '%s'", + registrationAlgorithm.getDataSetInformation())); + } else + { + getNotificationLog().error( + String.format(registrationAlgorithm.getErrorMessageTemplate(), + registrationAlgorithm.getDataSetInformation()), throwable); + } + // Errors which are not AssertionErrors leave the system in a state that we don't + // know and can't trust. Thus we will not perform any operations any more in this + // case. + if (throwable instanceof Error && throwable instanceof AssertionError == false) + { + throw (Error) throwable; + } + UnstoreDataAction action = registrationAlgorithm.rollbackStorageProcessor(throwable); + if (stopped == false) + { + if (action == UnstoreDataAction.MOVE_TO_ERROR) + { + final File baseDirectory = + registrationAlgorithm.createBaseDirectory( + TransferredDataSetHandler.ERROR_DATA_STRATEGY, + registrationAlgorithm.getStoreRoot(), + registrationAlgorithm.getDataSetInformation()); + registrationAlgorithm.setBaseDirectoryHolder(new BaseDirectoryHolder( + TransferredDataSetHandler.ERROR_DATA_STRATEGY, baseDirectory, + incomingDataSetFile)); + boolean moveInCaseOfErrorOk = + FileRenamer.renameAndLog(incomingDataSetFile, registrationAlgorithm + .getBaseDirectoryHolder().getTargetFile()); + writeThrowable(); + if (moveInCaseOfErrorOk) + { + registrationAlgorithm.clean(); + } + } else if (action == UnstoreDataAction.DELETE) + { + FileUtilities.deleteRecursively(incomingDataSetFile, new Log4jSimpleLogger( + TransferredDataSetHandler.operationLog)); + } + } + } + + private Logger getNotificationLog() + { + return notificationLog; + } + + private Logger getOperationLog() + { + return operationLog; + } + + protected final void writeThrowable() + { + final String fileName = incomingDataSetFile.getName() + ".exception"; + final File file = + new File(registrationAlgorithm.getBaseDirectoryHolder().getTargetFile() + .getParentFile(), fileName); + FileWriter writer = null; + try + { + writer = new FileWriter(file); + throwable.printStackTrace(new PrintWriter(writer)); + } catch (final IOException e) + { + TransferredDataSetHandler.operationLog.warn(String.format( + "Could not write out the exception '%s' in file '%s'.", fileName, + file.getAbsolutePath()), e); + } finally + { + IOUtils.closeQuietly(writer); + } + } +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataStoreStrategyKey.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataStoreStrategyKey.java index c162760ea48deea523738641973784fbac7c0e5e..5aa0504c3a8b92b07768a0cb474ce8291afe4428 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataStoreStrategyKey.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/DataStoreStrategyKey.java @@ -23,13 +23,13 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; * * @author Christian Ribeaud */ -enum DataStoreStrategyKey +public enum DataStoreStrategyKey { /** - * This <code>IDataStoreStrategy</code> implementation if for data set that has been - * identified as <i>unidentified</i>, meaning that, for instance, no experiment could be mapped - * to the one found in given {@link DataSetInformation} (if we try to find out the sample to - * which this data set should be registered through the experiment). + * This <code>IDataStoreStrategy</code> implementation if for data set that has been identified + * as <i>unidentified</i>, meaning that, for instance, no experiment could be mapped to the one + * found in given {@link DataSetInformation} (if we try to find out the sample to which this + * data set should be registered through the experiment). */ UNIDENTIFIED, /** @@ -39,10 +39,10 @@ enum DataStoreStrategyKey */ IDENTIFIED, /** - * This <code>IDataStoreStrategy</code> implementation if for data set that has been - * identified as <i>invalid</i>, meaning that the data set itself or its - * <code>Master Plate</code> code is not registered in the database. So there is no - * possibility to link the data set to an already existing sample. + * This <code>IDataStoreStrategy</code> implementation if for data set that has been identified + * as <i>invalid</i>, meaning that the data set itself or its <code>Master Plate</code> code is + * not registered in the database. So there is no possibility to link the data set to an already + * existing sample. */ INVALID, /** diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/IDataStoreStrategy.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/IDataStoreStrategy.java index c5ea87451e33b1b865e490e5d9188fac49b4c56e..ed58161928a1471c626553ed66fa7bb8e37f43ed 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/IDataStoreStrategy.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/IDataStoreStrategy.java @@ -26,7 +26,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; * * @author Christian Ribeaud */ -interface IDataStoreStrategy +public interface IDataStoreStrategy { /** @@ -44,7 +44,8 @@ interface IDataStoreStrategy final DataSetType dataSetType); /** - * Create the target path for given <var>baseDirectory</var> and given <var>incomingDataSetPath</var>. + * Create the target path for given <var>baseDirectory</var> and given + * <var>incomingDataSetPath</var>. * <p> * Note that each call either produces a new <i>target path</i> or throws an exception if * computed <i>target path</i> already exists. diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/PropertiesBasedETLServerPlugin.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/PropertiesBasedETLServerPlugin.java index 2f788d8332f4ef085218591dc26e89b5a2a25eee..d14eb8de180be243ea2586e88a8795691b3097f1 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/PropertiesBasedETLServerPlugin.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/PropertiesBasedETLServerPlugin.java @@ -74,7 +74,10 @@ public class PropertiesBasedETLServerPlugin extends ETLServerPlugin private static final Properties EMPTY_PROPERTIES = new Properties(); - private final static <T> T create(final Class<T> superClazz, final Properties properties, + /** + * Utility method to create objects from keys in the properties file. + */ + public final static <T> T create(final Class<T> superClazz, final Properties properties, final String keyPrefix, final boolean withSubset, final Object... arguments) { final String className = properties.getProperty(keyPrefix); 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 ef7a50a0cccb16d8fef77984e25f98250f5def56..2ec9fc42222de05dc544598c92d8d140c64cf5f7 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java @@ -29,15 +29,14 @@ 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.filesystem.FileOperations; -import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.common.filesystem.IFileOperations; -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.mail.IMailClient; import ch.systemsx.cisd.common.utilities.IDelegatedActionWithResult; import ch.systemsx.cisd.etlserver.DataSetRegistrationAlgorithm.IDataSetInApplicationServerRegistrator; -import ch.systemsx.cisd.etlserver.IStorageProcessor.UnstoreDataAction; +import ch.systemsx.cisd.etlserver.registrator.MarkerFileUtility; +import ch.systemsx.cisd.etlserver.registrator.TopLevelDataSetChecker; import ch.systemsx.cisd.etlserver.utils.PostRegistrationExecutor; import ch.systemsx.cisd.etlserver.utils.PreRegistrationExecutor; import ch.systemsx.cisd.etlserver.validation.IDataSetValidator; @@ -63,7 +62,7 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, TransferredDataSetHandler.class); - static final NamedDataStrategy ERROR_DATA_STRATEGY = new NamedDataStrategy( + public static final NamedDataStrategy ERROR_DATA_STRATEGY = new NamedDataStrategy( DataStoreStrategyKey.ERROR); private final IStoreRootDirectoryHolder storeRootDirectoryHolder; @@ -104,6 +103,8 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi private final IPostRegistrationAction postRegistrationAction; + private final MarkerFileUtility markerFileUtility; + /** * The designated constructor. * @@ -111,44 +112,8 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi */ public TransferredDataSetHandler(TopLevelDataSetRegistratorGlobalState globalState) { - super(globalState); - - this.dssCode = globalState.getDssCode(); - assert dssCode != null : "Unspecified data store code"; - - IETLServerPlugin plugin = - ETLServerPluginFactory.getPluginForThread(globalState.getThreadParameters()); - assert plugin != null : "IETLServerPlugin implementation can not be null."; - - storeRootDirectoryHolder = plugin.getStorageProcessor(); - assert storeRootDirectoryHolder != null : "Given store root directory holder can not be null."; - - this.limsService = globalState.getOpenBisService(); - assert limsService != null : "IEncapsulatedLimsService implementation can not be null."; - - this.mailClient = globalState.getMailClient(); - assert mailClient != null : "IMailClient implementation can not be null."; - - this.dataSetInfoExtractor = plugin.getDataSetInfoExtractor(); - this.typeExtractor = plugin.getTypeExtractor(); - this.storageProcessor = plugin.getStorageProcessor(); - dataSetHandler = plugin.getDataSetHandler(this, limsService); - if (dataSetHandler instanceof IDataSetHandlerWithMailClient) - { - ((IDataSetHandlerWithMailClient) dataSetHandler).initializeMailClient(mailClient); - } - this.dataSetValidator = globalState.getDataSetValidator(); - this.dataStrategyStore = new DataStrategyStore(this.limsService, mailClient); - this.notifySuccessfulRegistration = globalState.isNotifySuccessfulRegistration(); - this.registrationLock = new ReentrantLock(); - this.fileOperations = FileOperations.getMonitoredInstanceForCurrentThread(); - this.useIsFinishedMarkerFile = globalState.isUseIsFinishedMarkerFile(); - this.deleteUnidentified = globalState.isDeleteUnidentified(); - this.preRegistrationAction = - PreRegistrationExecutor.create(globalState.getPreRegistrationScriptOrNull()); - this.postRegistrationAction = - PostRegistrationExecutor.create(globalState.getPostRegistrationScriptOrNull()); - + this(globalState, ETLServerPluginFactory.getPluginForThread(globalState + .getThreadParameters())); } /** @@ -196,6 +161,10 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi this.postRegistrationAction = PostRegistrationExecutor.create(globalState.getPostRegistrationScriptOrNull()); + this.markerFileUtility = + new MarkerFileUtility(operationLog, notificationLog, fileOperations, + storeRootDirectoryHolder); + } /** @@ -221,8 +190,7 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi public List<DataSetInformation> handleDataSet(final File dataSet) { - final DataSetRegistrationHelper registrationHelper = - createRegistrationHelper(dataSet); + final DataSetRegistrationHelper registrationHelper = createRegistrationHelper(dataSet); return new DataSetRegistrationAlgorithmRunner(registrationHelper).runAlgorithm(); } @@ -248,27 +216,8 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi public final void check() throws ConfigurationFailureException, EnvironmentFailureException { - final File storeRootDirectory = storeRootDirectoryHolder.getStoreRootDirectory(); - storeRootDirectory.mkdirs(); - if (operationLog.isDebugEnabled()) - { - operationLog.debug("Checking store root directory '" - + storeRootDirectory.getAbsolutePath() + "'."); - } - final String errorMessage = - fileOperations.checkDirectoryFullyAccessible(storeRootDirectory, "store root"); - if (errorMessage != null) - { - if (fileOperations.exists(storeRootDirectory) == false) - { - throw EnvironmentFailureException.fromTemplate( - "Store root directory '%s' does not exist.", - storeRootDirectory.getAbsolutePath()); - } else - { - throw new ConfigurationFailureException(errorMessage); - } - } + new TopLevelDataSetChecker(operationLog, storeRootDirectoryHolder, fileOperations) + .runCheck(); } public boolean isRemote() @@ -300,8 +249,8 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi } } - private DataSetRegistrationHelper createRegistrationHelper( - File dataSet, DataSetInformation dataSetInformation, + private DataSetRegistrationHelper createRegistrationHelper(File dataSet, + DataSetInformation dataSetInformation, DataSetRegistrationAlgorithm.IDataSetInApplicationServerRegistrator registrator) { if (useIsFinishedMarkerFile) @@ -393,46 +342,12 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi */ private final File getIncomingDataSetPathFromMarker(final File isFinishedPath) { - final File incomingDataSetPath = - FileUtilities.removePrefixFromFileName(isFinishedPath, IS_FINISHED_PREFIX); - if (operationLog.isDebugEnabled()) - { - operationLog.debug(String.format( - "Getting incoming data set path '%s' from is-finished path '%s'", - incomingDataSetPath, isFinishedPath)); - } - final String errorMsg = - fileOperations.checkPathFullyAccessible(incomingDataSetPath, "incoming data set"); - if (errorMsg != null) - { - fileOperations.delete(isFinishedPath); - throw EnvironmentFailureException.fromTemplate(String.format( - "Error moving path '%s' from '%s' to '%s': %s", incomingDataSetPath.getName(), - incomingDataSetPath.getParent(), - storeRootDirectoryHolder.getStoreRootDirectory(), errorMsg)); - } - return incomingDataSetPath; + return markerFileUtility.getIncomingDataSetPathFromMarker(isFinishedPath); } private boolean deleteAndLogIsFinishedMarkerFile(File isFinishedFile) { - if (fileOperations.exists(isFinishedFile) == false) - { - return false; - } - final boolean ok = fileOperations.delete(isFinishedFile); - final String absolutePath = isFinishedFile.getAbsolutePath(); - if (ok == false) - { - notificationLog.error(String.format("Removing file '%s' failed.", absolutePath)); - } else - { - if (operationLog.isDebugEnabled()) - { - operationLog.debug(String.format("File '%s' has been removed.", absolutePath)); - } - } - return ok; + return markerFileUtility.deleteAndLogIsFinishedMarkerFile(isFinishedFile); } private class RegistrationHelper extends DataSetRegistrationHelper @@ -554,52 +469,9 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi protected void rollback(final Throwable throwable) throws Error { stopped |= throwable instanceof InterruptedExceptionUnchecked; - if (stopped) - { - Thread.interrupted(); // Ensure the thread's interrupted state is cleared. - getOperationLog().warn( - String.format("Requested to stop registration of data set '%s'", - registrationAlgorithm.getDataSetInformation())); - } else - { - getNotificationLog().error( - String.format(registrationAlgorithm.getErrorMessageTemplate(), - registrationAlgorithm.getDataSetInformation()), throwable); - } - // Errors which are not AssertionErrors leave the system in a state that we don't - // know and can't trust. Thus we will not perform any operations any more in this - // case. - if (throwable instanceof Error && throwable instanceof AssertionError == false) - { - throw (Error) throwable; - } - UnstoreDataAction action = registrationAlgorithm.rollbackStorageProcessor(throwable); - if (stopped == false) - { - if (action == UnstoreDataAction.MOVE_TO_ERROR) - { - final File baseDirectory = - registrationAlgorithm.createBaseDirectory( - TransferredDataSetHandler.ERROR_DATA_STRATEGY, - registrationAlgorithm.getStoreRoot(), - registrationAlgorithm.getDataSetInformation()); - registrationAlgorithm.setBaseDirectoryHolder(new BaseDirectoryHolder( - TransferredDataSetHandler.ERROR_DATA_STRATEGY, baseDirectory, - incomingDataSetFile)); - boolean moveInCaseOfErrorOk = - FileRenamer.renameAndLog(incomingDataSetFile, registrationAlgorithm - .getBaseDirectoryHolder().getTargetFile()); - writeThrowable(throwable); - if (moveInCaseOfErrorOk) - { - registrationAlgorithm.clean(); - } - } else if (action == UnstoreDataAction.DELETE) - { - FileUtilities.deleteRecursively(incomingDataSetFile, new Log4jSimpleLogger( - TransferredDataSetHandler.operationLog)); - } - } + + new DataSetRegistrationRollbacker(stopped, registrationAlgorithm, incomingDataSetFile, + notificationLog, operationLog, throwable).doRollback(); } } 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 new file mode 100644 index 0000000000000000000000000000000000000000..dbf96adc5b554f36f43008a470adaee80ea66fd9 --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/AbstractOmniscientTopLevelDataSetRegistrator.java @@ -0,0 +1,264 @@ +/* + * Copyright 2011 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.registrator; + +import static ch.systemsx.cisd.etlserver.IStorageProcessor.STORAGE_PROCESSOR_KEY; + +import java.io.File; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +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.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.utilities.IDelegatedActionWithResult; +import ch.systemsx.cisd.etlserver.AbstractTopLevelDataSetRegistrator; +import ch.systemsx.cisd.etlserver.DataSetRegistrationAlgorithm; +import ch.systemsx.cisd.etlserver.DataSetRegistrationAlgorithm.IRollbackDelegate; +import ch.systemsx.cisd.etlserver.DataSetRegistrationRollbacker; +import ch.systemsx.cisd.etlserver.DataStrategyStore; +import ch.systemsx.cisd.etlserver.IDataStrategyStore; +import ch.systemsx.cisd.etlserver.IPostRegistrationAction; +import ch.systemsx.cisd.etlserver.IPreRegistrationAction; +import ch.systemsx.cisd.etlserver.IStorageProcessor; +import ch.systemsx.cisd.etlserver.PropertiesBasedETLServerPlugin; +import ch.systemsx.cisd.etlserver.TopLevelDataSetRegistratorGlobalState; +import ch.systemsx.cisd.etlserver.utils.PostRegistrationExecutor; +import ch.systemsx.cisd.etlserver.utils.PreRegistrationExecutor; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; +import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public abstract class AbstractOmniscientTopLevelDataSetRegistrator extends + AbstractTopLevelDataSetRegistrator implements IRollbackDelegate +{ + static final Logger notificationLog = LogFactory.getLogger(LogCategory.NOTIFY, + AbstractOmniscientTopLevelDataSetRegistrator.class); + + static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, + AbstractOmniscientTopLevelDataSetRegistrator.class); + + protected static class OmniscientTopLevelDataSetRegistratorState + { + private final TopLevelDataSetRegistratorGlobalState globalState; + + private final IStorageProcessor storageProcessor; + + private final ReentrantLock registrationLock; + + private final IFileOperations fileOperations; + + private final IPreRegistrationAction preRegistrationAction; + + private final IPostRegistrationAction postRegistrationAction; + + private final IDataStrategyStore dataStrategyStore; + + private final MarkerFileUtility markerFileUtility; + + private OmniscientTopLevelDataSetRegistratorState( + TopLevelDataSetRegistratorGlobalState globalState, + IStorageProcessor storageProcessor, ReentrantLock registrationLock, + IFileOperations fileOperations) + { + this.globalState = globalState; + this.storageProcessor = storageProcessor; + this.registrationLock = registrationLock; + this.fileOperations = fileOperations; + this.dataStrategyStore = + new DataStrategyStore(globalState.getOpenBisService(), + globalState.getMailClient()); + this.preRegistrationAction = + PreRegistrationExecutor.create(globalState.getPreRegistrationScriptOrNull()); + this.postRegistrationAction = + PostRegistrationExecutor.create(globalState.getPostRegistrationScriptOrNull()); + this.markerFileUtility = + new MarkerFileUtility(operationLog, notificationLog, fileOperations, + storageProcessor); + } + + public TopLevelDataSetRegistratorGlobalState getGlobalState() + { + return globalState; + } + + public IStorageProcessor getStorageProcessor() + { + return storageProcessor; + } + + public ReentrantLock getRegistrationLock() + { + return registrationLock; + } + + public IFileOperations getFileOperations() + { + return fileOperations; + } + + public IPreRegistrationAction getPreRegistrationAction() + { + return preRegistrationAction; + } + + public IPostRegistrationAction getPostRegistrationAction() + { + return postRegistrationAction; + } + + public IDataStrategyStore getDataStrategyStore() + { + return dataStrategyStore; + } + + public MarkerFileUtility getMarkerFileUtility() + { + return markerFileUtility; + } + } + + private final OmniscientTopLevelDataSetRegistratorState state; + + private boolean stopped; + + /** + * @param globalState + */ + protected AbstractOmniscientTopLevelDataSetRegistrator( + TopLevelDataSetRegistratorGlobalState globalState) + { + super(globalState); + + state = + new OmniscientTopLevelDataSetRegistratorState(globalState, + PropertiesBasedETLServerPlugin.create(IStorageProcessor.class, globalState + .getThreadParameters().getThreadProperties(), + STORAGE_PROCESSOR_KEY, true), new ReentrantLock(), + FileOperations.getMonitoredInstanceForCurrentThread()); + + } + + public OmniscientTopLevelDataSetRegistratorState getRegistratorState() + { + return state; + } + + public Lock getRegistrationLock() + { + return state.registrationLock; + } + + public void handle(File incomingDataSetFileOrIsFinishedFile) + { + if (stopped) + { + return; + } + final File isFinishedFile = incomingDataSetFileOrIsFinishedFile; + final File incomingDataSetFile; + final IDelegatedActionWithResult<Boolean> cleanAfterwardsAction; + + if (getGlobalState().isUseIsFinishedMarkerFile()) + { + incomingDataSetFile = + state.getMarkerFileUtility().getIncomingDataSetPathFromMarker(isFinishedFile); + cleanAfterwardsAction = new IDelegatedActionWithResult<Boolean>() + { + public Boolean execute() + { + return state.getMarkerFileUtility().deleteAndLogIsFinishedMarkerFile( + isFinishedFile); + } + }; + } else + { + incomingDataSetFile = incomingDataSetFileOrIsFinishedFile; + cleanAfterwardsAction = new IDelegatedActionWithResult<Boolean>() + { + public Boolean execute() + { + return true; // do nothing + } + }; + } + + DataSetRegistrationService service = + new DataSetRegistrationService(this, cleanAfterwardsAction); + handleDataSet(incomingDataSetFile, service); + } + + public boolean isStopped() + { + return stopped; + } + + public boolean isRemote() + { + return true; + } + + // + // ISelfTestable + // + public final void check() throws ConfigurationFailureException, EnvironmentFailureException + { + new TopLevelDataSetChecker(operationLog, state.storageProcessor, state.fileOperations) + .runCheck(); + } + + /** + * For subclasses to override. + */ + public void rollback(DataSetRegistrationAlgorithm registrationAlgorithm, Throwable throwable) + { + updateStopped(throwable instanceof InterruptedExceptionUnchecked); + + new DataSetRegistrationRollbacker(stopped, registrationAlgorithm, + registrationAlgorithm.getIncomingDataSetFile(), notificationLog, operationLog, + throwable).doRollback(); + } + + public void registerDataSetInApplicationServer(DataSetInformation dataSetInformation, + NewExternalData data) throws Throwable + { + getGlobalState().getOpenBisService().registerDataSet(dataSetInformation, data); + } + + /** + * Update the value of stopped using the argument. + * <p> + * To be called by subclasses. + */ + protected void updateStopped(boolean update) + { + stopped |= update; + } + + /** + * For subclasses to override. + */ + protected abstract void handleDataSet(File dataSetFile, DataSetRegistrationService service); +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationDetails.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationDetails.java new file mode 100644 index 0000000000000000000000000000000000000000..045830a6f214f02a817a94f1d852cef6aae3f5bb --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationDetails.java @@ -0,0 +1,128 @@ +/* + * Copyright 2011 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.registrator; + +import java.io.File; + +import ch.systemsx.cisd.etlserver.ITypeExtractor; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LocatorType; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public class DataSetRegistrationDetails implements ITypeExtractor +{ + private FileFormatType fileFormatType; + + private boolean measuredData; + + private String processorType; + + private DataSetType dataSetType; + + private LocatorType locatorType; + + private DataSetInformation dataSetInformation; + + public FileFormatType getFileFormatType(File incomingDataSetPath) + { + return fileFormatType; + } + + public boolean isMeasuredData(File incomingDataSetPath) + { + return measuredData; + } + + public String getProcessorType(File incomingDataSetPath) + { + return processorType; + } + + public DataSetType getDataSetType(File incomingDataSetPath) + { + return dataSetType; + } + + public LocatorType getLocatorType(File incomingDataSetPath) + { + return locatorType; + } + + public FileFormatType getFileFormatType() + { + return fileFormatType; + } + + public void setFileFormatType(FileFormatType fileFormatType) + { + this.fileFormatType = fileFormatType; + } + + public boolean isMeasuredData() + { + return measuredData; + } + + public void setMeasuredData(boolean measuredData) + { + this.measuredData = measuredData; + } + + public String getProcessorType() + { + return processorType; + } + + public void setProcessorType(String processorType) + { + this.processorType = processorType; + } + + public DataSetType getDataSetType() + { + return dataSetType; + } + + public void setDataSetType(DataSetType dataSetType) + { + this.dataSetType = dataSetType; + } + + public LocatorType getLocatorType() + { + return locatorType; + } + + public void setLocatorType(LocatorType locatorType) + { + this.locatorType = locatorType; + } + + public DataSetInformation getDataSetInformation() + { + return dataSetInformation; + } + + public void setDataSetInformation(DataSetInformation dataSetInformation) + { + this.dataSetInformation = dataSetInformation; + } +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationService.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationService.java new file mode 100644 index 0000000000000000000000000000000000000000..d3a460abee489e20308e19d5056bc814e86f6cec --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationService.java @@ -0,0 +1,177 @@ +/* + * Copyright 2011 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.registrator; + +import java.io.File; +import java.util.ArrayList; + +import ch.systemsx.cisd.common.utilities.IDelegatedActionWithResult; +import ch.systemsx.cisd.etlserver.DataSetRegistrationAlgorithm; +import ch.systemsx.cisd.etlserver.DataSetRegistrationAlgorithm.DataSetRegistrationAlgorithmState; +import ch.systemsx.cisd.etlserver.DataSetRegistrationAlgorithm.IDataSetInApplicationServerRegistrator; +import ch.systemsx.cisd.etlserver.DataSetRegistrationAlgorithm.IRollbackDelegate; +import ch.systemsx.cisd.etlserver.IDataStoreStrategy; +import ch.systemsx.cisd.etlserver.TopLevelDataSetRegistratorGlobalState; +import ch.systemsx.cisd.etlserver.registrator.AbstractOmniscientTopLevelDataSetRegistrator.OmniscientTopLevelDataSetRegistratorState; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; +import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData; + +/** + * A service that registers many files as individual data sets in one transaction. + * + * @author Chandrasekhar Ramakrishnan + */ +public class DataSetRegistrationService implements IRollbackDelegate +{ + private final AbstractOmniscientTopLevelDataSetRegistrator registrator; + + private final OmniscientTopLevelDataSetRegistratorState registratorState; + + private final IDelegatedActionWithResult<Boolean> globalCleanAfterwardsAction; + + private final ArrayList<DataSetRegistrationAlgorithm> dataSetRegistrations = + new ArrayList<DataSetRegistrationAlgorithm>(); + + /** + * A data set that will be created but might not yet exist. + * + * @author Chandrasekhar Ramakrishnan + */ + public class FutureDataSet + { + private final String code; + + public FutureDataSet(String code) + { + this.code = code; + } + + public String getCode() + { + return code; + } + } + + public DataSetRegistrationService(AbstractOmniscientTopLevelDataSetRegistrator registrator, + IDelegatedActionWithResult<Boolean> globalCleanAfterwardsAction) + { + this.registrator = registrator; + this.registratorState = registrator.getRegistratorState(); + this.globalCleanAfterwardsAction = globalCleanAfterwardsAction; + } + + /** + * Factory method that creates a new registration details object. + */ + public DataSetRegistrationDetails createRegistrationDetails() + { + return new DataSetRegistrationDetails(); + } + + /** + * Factory method that creates a new data set information object. + */ + public DataSetInformation createDataSetInformation() + { + return new DataSetInformation(); + } + + /** + * Queue registration a data set and return a future for the data set that will be created. + */ + public FutureDataSet queueDataSetRegistration(File dataSetFile, + DataSetRegistrationDetails details) + { + DataSetRegistrationAlgorithm registration = + createRegistrationAlgorithm(dataSetFile, details); + dataSetRegistrations.add(registration); + + FutureDataSet future = + new FutureDataSet(registration.getDataSetInformation().getDataSetCode()); + return future; + } + + public void commit() + { + + globalCleanAfterwardsAction.execute(); + } + + public void abort() + { + + } + + private DataSetRegistrationAlgorithm createRegistrationAlgorithm(File incomingDataSetFile, + DataSetRegistrationDetails details) + { + final TopLevelDataSetRegistratorGlobalState globalState = registratorState.getGlobalState(); + final IDelegatedActionWithResult<Boolean> cleanAfterwardsAction = + new IDelegatedActionWithResult<Boolean>() + { + public Boolean execute() + { + return true; // do nothing + } + }; + + IDataStoreStrategy dataStoreStrategy = + registratorState.getDataStrategyStore().getDataStoreStrategy( + details.getDataSetInformation(), incomingDataSetFile); + + DataSetRegistrationAlgorithmState state = + new DataSetRegistrationAlgorithmState(incomingDataSetFile, + globalState.getOpenBisService(), cleanAfterwardsAction, + registratorState.getPreRegistrationAction(), + registratorState.getPostRegistrationAction(), + details.getDataSetInformation(), dataStoreStrategy, details, + registratorState.getStorageProcessor(), + registratorState.getFileOperations(), globalState.getDataSetValidator(), + globalState.getMailClient(), globalState.isDeleteUnidentified(), + registratorState.getRegistrationLock(), globalState.getDssCode(), + globalState.isNotifySuccessfulRegistration()); + return new DataSetRegistrationAlgorithm(state, this, + new DefaultApplicationServerRegistrator(registrator, + details.getDataSetInformation())); + } + + public void rollback(DataSetRegistrationAlgorithm algorithm, Throwable ex) + { + registrator.rollback(algorithm, ex); + } + + private static class DefaultApplicationServerRegistrator implements + IDataSetInApplicationServerRegistrator + { + private final AbstractOmniscientTopLevelDataSetRegistrator registrator; + + private final DataSetInformation dataSetInformation; + + DefaultApplicationServerRegistrator(AbstractOmniscientTopLevelDataSetRegistrator registrator, + DataSetInformation dataSetInformation) + { + this.dataSetInformation = dataSetInformation; + this.registrator = registrator; + } + + public void registerDataSetInApplicationServer(NewExternalData data) throws Throwable + { + registrator.registerDataSetInApplicationServer(dataSetInformation, data); + } + + } +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/MarkerFileUtility.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/MarkerFileUtility.java new file mode 100644 index 0000000000000000000000000000000000000000..4761e4390c47021dc2ba4bdf7f573203c2031081 --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/MarkerFileUtility.java @@ -0,0 +1,101 @@ +/* + * Copyright 2011 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.registrator; + +import static ch.systemsx.cisd.common.Constants.IS_FINISHED_PREFIX; + +import java.io.File; + +import org.apache.log4j.Logger; + +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.filesystem.IFileOperations; +import ch.systemsx.cisd.etlserver.IStoreRootDirectoryHolder; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public class MarkerFileUtility +{ + private final Logger operationLog; + + private final Logger notificationLog; + + private final IFileOperations fileOperations; + + private final IStoreRootDirectoryHolder storeRootDirectoryHolder; + + public MarkerFileUtility(Logger operationLog, Logger notificationLog, + IFileOperations fileOperations, IStoreRootDirectoryHolder storeRootDirectoryHolder) + { + this.operationLog = operationLog; + this.notificationLog = notificationLog; + this.fileOperations = fileOperations; + this.storeRootDirectoryHolder = storeRootDirectoryHolder; + } + + /** + * From given <var>isFinishedPath</var> gets the incoming data set path and checks it. + * + * @return <code>null</code> if a problem has happened. Otherwise a useful and usable incoming + * data set path is returned. + */ + public final File getIncomingDataSetPathFromMarker(final File isFinishedPath) + { + final File incomingDataSetPath = + FileUtilities.removePrefixFromFileName(isFinishedPath, IS_FINISHED_PREFIX); + if (operationLog.isDebugEnabled()) + { + operationLog.debug(String.format( + "Getting incoming data set path '%s' from is-finished path '%s'", + incomingDataSetPath, isFinishedPath)); + } + final String errorMsg = + fileOperations.checkPathFullyAccessible(incomingDataSetPath, "incoming data set"); + if (errorMsg != null) + { + fileOperations.delete(isFinishedPath); + throw EnvironmentFailureException.fromTemplate(String.format( + "Error moving path '%s' from '%s' to '%s': %s", incomingDataSetPath.getName(), + incomingDataSetPath.getParent(), + storeRootDirectoryHolder.getStoreRootDirectory(), errorMsg)); + } + return incomingDataSetPath; + } + + public boolean deleteAndLogIsFinishedMarkerFile(File isFinishedFile) + { + if (fileOperations.exists(isFinishedFile) == false) + { + return false; + } + final boolean ok = fileOperations.delete(isFinishedFile); + final String absolutePath = isFinishedFile.getAbsolutePath(); + if (ok == false) + { + notificationLog.error(String.format("Removing file '%s' failed.", absolutePath)); + } else + { + if (operationLog.isDebugEnabled()) + { + operationLog.debug(String.format("File '%s' has been removed.", absolutePath)); + } + } + return ok; + } +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/TopLevelDataSetChecker.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/TopLevelDataSetChecker.java new file mode 100644 index 0000000000000000000000000000000000000000..2c9059e65a55451299e05adbb858391371d95ad7 --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/TopLevelDataSetChecker.java @@ -0,0 +1,72 @@ +/* + * Copyright 2011 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.registrator; + +import java.io.File; + +import org.apache.log4j.Logger; + +import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.filesystem.IFileOperations; +import ch.systemsx.cisd.etlserver.IStoreRootDirectoryHolder; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public class TopLevelDataSetChecker +{ + private final Logger operationLog; + + private final IStoreRootDirectoryHolder storeRootDirectoryHolder; + + private final IFileOperations fileOperations; + + public TopLevelDataSetChecker(Logger operationLog, + IStoreRootDirectoryHolder storeRootDirectoryHolder, IFileOperations fileOperations) + { + this.operationLog = operationLog; + this.storeRootDirectoryHolder = storeRootDirectoryHolder; + this.fileOperations = fileOperations; + } + + public void runCheck() + { + + final File storeRootDirectory = storeRootDirectoryHolder.getStoreRootDirectory(); + storeRootDirectory.mkdirs(); + if (operationLog.isDebugEnabled()) + { + operationLog.debug("Checking store root directory '" + + storeRootDirectory.getAbsolutePath() + "'."); + } + final String errorMessage = + fileOperations.checkDirectoryFullyAccessible(storeRootDirectory, "store root"); + if (errorMessage != null) + { + if (fileOperations.exists(storeRootDirectory) == false) + { + throw EnvironmentFailureException.fromTemplate( + "Store root directory '%s' does not exist.", + storeRootDirectory.getAbsolutePath()); + } else + { + throw new ConfigurationFailureException(errorMessage); + } + } + } +} diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithmTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithmTest.java index 99f2c62ad3c33629d4b75f19b57c3e903b16ad5b..c2c1ed66a764274a7a1c7831a13a1d568dcc4994 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithmTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/DataSetRegistrationAlgorithmTest.java @@ -84,7 +84,7 @@ public class DataSetRegistrationAlgorithmTest extends AbstractFileSystemTestCase private IDataSetInApplicationServerRegistrator appServerRegistrator; - private IDelegatedActionWithResult<Boolean> cleanAftrewardsAction; + private IDelegatedActionWithResult<Boolean> cleanAfterwardsAction; private IPreRegistrationAction preRegistrationAction; @@ -122,7 +122,7 @@ public class DataSetRegistrationAlgorithmTest extends AbstractFileSystemTestCase openBisService = context.mock(IEncapsulatedOpenBISService.class); rollbackDelegate = context.mock(IRollbackDelegate.class); appServerRegistrator = context.mock(IDataSetInApplicationServerRegistrator.class); - cleanAftrewardsAction = context.mock(IDelegatedActionWithResult.class); + cleanAfterwardsAction = context.mock(IDelegatedActionWithResult.class); preRegistrationAction = context.mock(IPreRegistrationAction.class); postRegistrationAction = context.mock(IPostRegistrationAction.class); @@ -437,7 +437,7 @@ public class DataSetRegistrationAlgorithmTest extends AbstractFileSystemTestCase context.checking(new Expectations() { { - exactly(2).of(cleanAftrewardsAction).execute(); + exactly(2).of(cleanAfterwardsAction).execute(); will(returnValue(Boolean.TRUE)); } }); @@ -457,11 +457,10 @@ public class DataSetRegistrationAlgorithmTest extends AbstractFileSystemTestCase private void createAlgorithmAndState(boolean shouldDeleteUnidentified, boolean shouldNotifySuccessfulRegistration) { - String dataStoreCode = DATA_STORE_CODE; DataSetRegistrationAlgorithmState state = new DataSetRegistrationAlgorithmState(incomingDataSetFile, openBisService, - cleanAftrewardsAction, preRegistrationAction, postRegistrationAction, + cleanAfterwardsAction, preRegistrationAction, postRegistrationAction, dataSetInformation, dataStoreStrategy, typeExtractor, storageProcessor, fileOperations, dataSetValidator, mailClient, shouldDeleteUnidentified, registrationLock, dataStoreCode, shouldNotifySuccessfulRegistration);