diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ProcessDatasetsCommand.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ProcessDatasetsCommand.java index 0e96916748266ceb1c0595952c6ecc372f6e20d1..d77e41bfcaf4c3230ddcf4cb5bb9508155f21ecd 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ProcessDatasetsCommand.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ProcessDatasetsCommand.java @@ -21,11 +21,13 @@ import java.util.List; import org.apache.log4j.Logger; +import ch.systemsx.cisd.common.exceptions.Status; 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.mail.MailClient; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IProcessingPluginTask; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.ProcessingStatus; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatastoreServiceDescription; import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; @@ -66,9 +68,10 @@ public class ProcessDatasetsCommand implements IDataSetCommand public void execute(File store) { String errorMessageOrNull = null; + ProcessingStatus processingStatusOrNull = null; try { - task.process(datasets); + processingStatusOrNull = task.process(datasets); } catch (RuntimeException e) { // exception message should be readable for users @@ -91,26 +94,33 @@ public class ProcessDatasetsCommand implements IDataSetCommand } return; } - createContentAndSendMessage(errorMessageOrNull); + createContentAndSendMessage(errorMessageOrNull, processingStatusOrNull); } } - private void createContentAndSendMessage(String errorMessageOrNull) + private void createContentAndSendMessage(String errorMessageOrNull, + ProcessingStatus processingStatusOrNull) { final StringBuilder contentBuilder = new StringBuilder(); final String subject; if (errorMessageOrNull != null) { // create error message content - subject = getShortDescription("Failed to perform "); + subject = getShortDescription(" processing failed"); contentBuilder.append(getDescription(subject)); contentBuilder.append("\n\nError message:\n"); contentBuilder.append(errorMessageOrNull); } else { // create success message content - subject = getShortDescription("Finished "); - contentBuilder.append(getDescription(subject)); + subject = getShortDescription(" processing finished"); + if (processingStatusOrNull != null) + { + contentBuilder.append(generateDescription(processingStatusOrNull)); + } else + { + contentBuilder.append(getDescription(subject)); + } } sendMessage(subject, contentBuilder.toString(), userEmailOrNull); } @@ -126,14 +136,14 @@ public class ProcessDatasetsCommand implements IDataSetCommand mailClient.sendMessage(subject, content, null, null, recipient); } - private String getShortDescription(String prefix) + private String getShortDescription(String suffix) { - return String.format("%s'%s'", prefix, serviceDescription.getLabel()); + return String.format("'%s'%s", serviceDescription.getLabel(), suffix); } private String getDescription(String prefix) { - return String.format("%s on data set(s): [%s]", prefix, getDataSetCodes()); + return String.format("%s on data set(s): \n%s", prefix, getDataSetCodes(datasets)); } public String getDescription() @@ -141,7 +151,7 @@ public class ProcessDatasetsCommand implements IDataSetCommand return getDescription(getShortDescription("")); } - public String getDataSetCodes() + private static String getDataSetCodes(List<DatasetDescription> datasets) { if (datasets.isEmpty()) { @@ -158,4 +168,25 @@ public class ProcessDatasetsCommand implements IDataSetCommand return sb.toString(); } } + + private static String generateDescription(ProcessingStatus processingStatus) + { + StringBuilder sb = new StringBuilder(); + sb.append("Data sets:\n"); + List<DatasetDescription> successfullyProcessed = + processingStatus.getDatasetsByStatus(Status.OK); + if (successfullyProcessed.isEmpty() == false) + { + sb.append("- successfully processed: "); + sb.append(getDataSetCodes(successfullyProcessed)); + } + List<Status> errorStatuses = processingStatus.getErrorStatuses(); + for (Status errorStatus : errorStatuses) + { + sb.append("\n- " + errorStatus.tryGetErrorMessage() + ": "); + sb.append(getDataSetCodes(successfullyProcessed)); + } + return sb.toString(); + } + } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoProcessingPlugin.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoProcessingPlugin.java index b8b154f0563782ca6fdd918f8f87c512b7d14186..7a531679f3d403bdd93406dcd2217cf8e4d8e0ba 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoProcessingPlugin.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoProcessingPlugin.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Properties; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IProcessingPluginTask; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.ProcessingStatus; import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; /** @@ -36,7 +37,7 @@ public class DemoProcessingPlugin implements IProcessingPluginTask { } - public void process(List<DatasetDescription> datasets) + public ProcessingStatus process(List<DatasetDescription> datasets) { System.out.println("Processing of the following datasets has been requested: " + datasets); System.out.println("sleeping for 10 sec"); @@ -48,6 +49,6 @@ public class DemoProcessingPlugin implements IProcessingPluginTask ex.printStackTrace(); } System.out.println("Processing done."); + return null; } - } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/AbstractDropboxProcessingPlugin.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/AbstractDropboxProcessingPlugin.java index 4cfeb8c433b940217430760211b5bd9ebb0b0625..7d252c834d97c4608174153096af0671233f8f2e 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/AbstractDropboxProcessingPlugin.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/AbstractDropboxProcessingPlugin.java @@ -22,10 +22,12 @@ import java.util.Properties; import org.apache.log4j.Logger; +import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IProcessingPluginTask; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.ProcessingStatus; import ch.systemsx.cisd.openbis.dss.generic.shared.IPostRegistrationDatasetHandler; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; @@ -42,7 +44,13 @@ abstract public class AbstractDropboxProcessingPlugin extends AbstractDatastoreP private static final long serialVersionUID = 1L; final static Logger operationLog = - LogFactory.getLogger(LogCategory.OPERATION, IPostRegistrationDatasetHandler.class); + LogFactory.getLogger(LogCategory.OPERATION, AbstractDropboxProcessingPlugin.class); + + private final static String MISSING_DIRECTORY_MSG = "with missing directory"; + + private final static String EMPTY_DIRECTORY_MSG = "with empty directory"; + + private final static String MORE_THAN_ONE_ITEM_MSG = "with more than one item in the directory"; private final IPostRegistrationDatasetHandler dropboxHandler; @@ -57,30 +65,40 @@ abstract public class AbstractDropboxProcessingPlugin extends AbstractDatastoreP this.dropboxHandler = dropboxHandler; } - public void process(List<DatasetDescription> datasets) + public ProcessingStatus process(List<DatasetDescription> datasets) { + final ProcessingStatus result = new ProcessingStatus(); for (DatasetDescription dataset : datasets) { - File originalDir = getDataSubDir(dataset); - if (originalDir.isDirectory() == false) - { - operationLog - .warn("Dataset directory does not exist and will be silently excluded from the processing: " - + originalDir.getPath()); - continue; - } - File[] datasetFiles = FileUtilities.listFiles(originalDir); - if (datasetFiles.length == 1) - { - DataSetInformation datasetInfo = createDatasetInfo(dataset); - dropboxHandler.handle(datasetFiles[0], datasetInfo); - } else if (datasetFiles.length > 1) - { - operationLog.error(String.format( - "Exactly one item was expected in the '%s' directory," - + " but %d have been found. Nothing will be processed.", - originalDir.getParent(), datasetFiles.length)); - } + Status status = processDataset(dataset); + result.addDatasetStatus(dataset, status); + } + return result; + } + + private Status processDataset(DatasetDescription dataset) + { + File originalDir = getDataSubDir(dataset); + if (originalDir.isDirectory() == false) + { + operationLog + .warn("Dataset directory does not exist and will be silently excluded from the processing: " + + originalDir.getPath()); + return Status.createError(MISSING_DIRECTORY_MSG); + } + File[] datasetFiles = FileUtilities.listFiles(originalDir); + if (datasetFiles.length == 1) + { + DataSetInformation datasetInfo = createDatasetInfo(dataset); + return dropboxHandler.handle(datasetFiles[0], datasetInfo); + } else + { + operationLog.error(String.format("Exactly one item was expected in the '%s' directory," + + " but %d have been found. Nothing will be processed.", originalDir + .getParent(), datasetFiles)); + final String errorMsg = + datasetFiles.length > 1 ? MORE_THAN_ONE_ITEM_MSG : EMPTY_DIRECTORY_MSG; + return Status.createError(errorMsg); } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/DataSetCopier.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/DataSetCopier.java index 035c6c871bc700dbbe6c3411cc904f0a2d763f9a..cf3419a2e604991a719d56f3c98bcf080703da8d 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/DataSetCopier.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/DataSetCopier.java @@ -23,7 +23,6 @@ import java.util.Properties; import ch.rinn.restrictions.Private; import ch.systemsx.cisd.base.utilities.OSUtilities; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; -import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.common.filesystem.IPathCopier; @@ -55,6 +54,10 @@ public class DataSetCopier extends AbstractDropboxProcessingPlugin @Private static final String RSYNC_PASSWORD_FILE_KEY = "rsync-password-file"; + private static final String ALREADY_EXIST_MSG = "already exist"; + + private static final String COPYING_FAILED_MSG = "copying failed"; + private static final String RSYNC_EXEC = "rsync"; private static final String SSH_EXEC = "ssh"; @@ -128,18 +131,40 @@ public class DataSetCopier extends AbstractDropboxProcessingPlugin return copier; } - public void handle(File originalData, DataSetInformation dataSetInformation) + public Status handle(File originalData, DataSetInformation dataSetInformation) { + if (checkDestinationExists()) + { + operationLog.error("Destination directory '" + destination.getPath() + + "' already exists - dataset files will not be copied."); + return Status.createError(ALREADY_EXIST_MSG); + } Status status = getCopier().copyToRemote(originalData, destination, host, rsyncModule, rsyncPasswordFile); if (status.isError()) { - throw new EnvironmentFailureException("Could not copy data set " - + dataSetInformation.getDataSetCode() + " to destination folder '" - + destination + "'" + (host != null ? " on host '" + host + "'" : "") + operationLog.error("Could not copy data set " + dataSetInformation.getDataSetCode() + + " to destination folder '" + destination + "'" + + (host != null ? " on host '" + host + "'" : "") + (rsyncModule != null ? " for rsync module '" + rsyncModule + "'" : "") + ": " + status.tryGetErrorMessage()); + return Status.createError(COPYING_FAILED_MSG); + } + return status; + } + + private boolean checkDestinationExists() + { + if (host != null) + { + // TODO 2010-01-29, Piotr Buczek: check if directory already exists + // check remotely using ssh + return false; + } else + { + // check locally + return destination.exists(); } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/IProcessingPluginTask.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/IProcessingPluginTask.java index 6b9bd6a56ee06da65684b7090eb7574e51f6b313..6bcbcf8c376f463b41a288e6cdc6e1d8ae6fb0f4 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/IProcessingPluginTask.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/IProcessingPluginTask.java @@ -30,7 +30,11 @@ public interface IProcessingPluginTask extends Serializable { /** * Processes asynchronously the specified datasets. + * + * @returns {@link ProcessingStatus} of the finished processing with statuses of processing for + * all scheduled data sets or null if processing succeeded for all datasets and no + * additional information is provided. */ - void process(List<DatasetDescription> datasets); + ProcessingStatus process(List<DatasetDescription> datasets); } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/ProcessingStatus.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/ProcessingStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..805dc09bd9cfcf11a0798515df552941ab4ba980 --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/ProcessingStatus.java @@ -0,0 +1,61 @@ +/* + * 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.openbis.dss.generic.server.plugins.tasks; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import ch.systemsx.cisd.common.exceptions.Status; +import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; + +/** + * Holder of finished processing {@link Status}es of all handled data sets. + * + * @author Piotr Buczek + */ +public class ProcessingStatus +{ + + private Map<Status, List<DatasetDescription>> datasetByStatus = + new LinkedHashMap<Status, List<DatasetDescription>>(); + + public void addDatasetStatus(DatasetDescription dataset, Status status) + { + List<DatasetDescription> datasets = datasetByStatus.get(status); + if (datasets == null) + { + datasets = new ArrayList<DatasetDescription>(); + datasetByStatus.put(status, datasets); + } + datasets.add(dataset); + } + + public List<Status> getErrorStatuses() + { + List<Status> result = new ArrayList<Status>(datasetByStatus.keySet()); + result.remove(Status.OK); + return result; + } + + public List<DatasetDescription> getDatasetsByStatus(Status status) + { + return datasetByStatus.get(status); + } + +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IPostRegistrationDatasetHandler.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IPostRegistrationDatasetHandler.java index c91fbd3abb92348cbb0a769f9ffc7d358a735c35..7196facb9ac0602ecf06138180e1037597d8d194 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IPostRegistrationDatasetHandler.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IPostRegistrationDatasetHandler.java @@ -18,20 +18,23 @@ package ch.systemsx.cisd.openbis.dss.generic.shared; import java.io.File; +import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; /** * Handler of data sets after successful registration in openBIS. - * + * * @author Franz-Josef Elmer */ public interface IPostRegistrationDatasetHandler { /** - * Handles specified original data file by using specified data set information. - * Note, that <code>originalData</code> is already the path inside the data store. + * Handles specified original data file by using specified data set information. Note, that + * <code>originalData</code> is already the path inside the data store. + * + * @return {@link Status} of the operation. */ - public void handle(File originalData, final DataSetInformation dataSetInformation); + public Status handle(File originalData, final DataSetInformation dataSetInformation); /** * Reverts the previous invocation of {@link #handle(File, DataSetInformation)}. diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/AbstractDatasetDropboxHandler.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/AbstractDatasetDropboxHandler.java index a47276ea2ceba836b63453087c3fd5a6a9b0fabb..5919258de1471db349f8f59cf8fc39a5946fc6a6 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/AbstractDatasetDropboxHandler.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/AbstractDatasetDropboxHandler.java @@ -26,6 +26,7 @@ import org.apache.log4j.Logger; import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.common.filesystem.FileOperations; import ch.systemsx.cisd.common.filesystem.IFileOperations; import ch.systemsx.cisd.common.logging.LogCategory; @@ -44,7 +45,8 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; * * @author Tomasz Pylak */ -abstract public class AbstractDatasetDropboxHandler implements Serializable, IPostRegistrationDatasetHandler +abstract public class AbstractDatasetDropboxHandler implements Serializable, + IPostRegistrationDatasetHandler { private static final long serialVersionUID = 1L; @@ -123,7 +125,7 @@ abstract public class AbstractDatasetDropboxHandler implements Serializable, IPo return file; } - public final void handle(File originalData, final DataSetInformation dataSetInformation) + public final Status handle(File originalData, final DataSetInformation dataSetInformation) { File dropboxDir = tryGetDropboxDir(originalData, dataSetInformation); if (dropboxDir != null) @@ -132,6 +134,7 @@ abstract public class AbstractDatasetDropboxHandler implements Serializable, IPo createDropboxDestinationFileName(dataSetInformation, originalData); copy(originalData, dropboxDir, destinationFileName); } + return Status.OK; } private void copy(File originalData, File dropboxDir, String destinationFileName)