Coverage Summary for Class: ExportDms (org.kitodo.export)

Class Class, % Method, % Line, %
ExportDms 100% (1/1) 13% (3/23) 14,7% (23/156)


 /*
  * (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org>
  *
  * This file is part of the Kitodo project.
  *
  * It is licensed under GNU General Public License version 3 or later.
  *
  * For the full copyright and license information, please read the
  * GPL3-License.txt file that was distributed with this source code.
  */
 
 package org.kitodo.export;
 
 import java.io.File;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Collection;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.kitodo.config.ConfigCore;
 import org.kitodo.config.enums.ParameterCore;
 import org.kitodo.data.database.beans.Folder;
 import org.kitodo.data.database.beans.Process;
 import org.kitodo.data.database.beans.Task;
 import org.kitodo.data.database.exceptions.DAOException;
 import org.kitodo.data.elasticsearch.index.converter.ProcessConverter;
 import org.kitodo.data.exceptions.DataException;
 import org.kitodo.exceptions.ExportException;
 import org.kitodo.exceptions.MetadataException;
 import org.kitodo.production.helper.Helper;
 import org.kitodo.production.helper.VariableReplacer;
 import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyDocStructHelperInterface;
 import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyMetadataHelper;
 import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyMetsModsDigitalDocumentHelper;
 import org.kitodo.production.helper.tasks.EmptyTask;
 import org.kitodo.production.helper.tasks.ExportDmsTask;
 import org.kitodo.production.helper.tasks.TaskManager;
 import org.kitodo.production.helper.tasks.TaskSitter;
 import org.kitodo.production.metadata.copier.CopierData;
 import org.kitodo.production.metadata.copier.DataCopier;
 import org.kitodo.production.model.Subfolder;
 import org.kitodo.production.services.ServiceManager;
 import org.kitodo.production.services.data.ProcessService;
 import org.kitodo.production.services.file.FileService;
 import org.kitodo.production.services.workflow.WorkflowControllerService;
 
 public class ExportDms extends ExportMets {
     private static final Logger logger = LogManager.getLogger(ExportDms.class);
     private static final String COMPLETED = "100000000000";
     private static final String EXPORT_DIR_DELETE = "errorDirectoryDeleting";
     private static final String ERROR_EXPORT = "errorExport";
 
     private final FileService fileService = ServiceManager.getFileService();
     private final ProcessService processService = ServiceManager.getProcessService();
 
     private boolean exportWithImages = true;
 
     private Task workFlowTask;
 
     public ExportDms() {
     }
 
     public ExportDms(boolean exportImages) {
         this.exportWithImages = exportImages;
     }
 
     public ExportDms(Task workFlowTask) {
         this.workFlowTask = workFlowTask;
     }
 
     /**
      * Export to DMS.
      *
      * @param task
      *            Task object
      * @throws IOException
      *             if I/O fails while running a script for a script condition of
      *             a subsequent task, or the METS file cannot be read when
      *             evaluating an XPath condition
      */
     public void startExport(Task task) throws DataException, IOException, DAOException {
         if (startExport(task.getProcess())) {
             new WorkflowControllerService().close(task);
         }
     }
 
     /**
      * Export to DMS.
      *
      * @param process
      *            Process object
      */
     @Override
     public boolean startExport(Process process) throws DataException {
         if (!exportCompletedChildren(process.getChildren())) {
             return false;
         }
 
         boolean wasNotAlreadyExported = !process.isExported();
         if (wasNotAlreadyExported) {
             process.setExported(true);
             processService.save(process);
         }
 
         boolean exportSuccessful = startExport(process, (URI) null);
         if (exportSuccessful) {
             if (Objects.nonNull(process.getParent())) {
                 startExport(process.getParent());
             }
         } else if (wasNotAlreadyExported) {
             process.setExported(false);
             processService.save(process);
         }
         return exportSuccessful;
     }
 
     /**
      * Export to the DMS.
      *
      * @param process
      *            process to export
      * @param unused
      *            user home directory
      */
     @Override
     public boolean startExport(Process process, URI unused) {
         if (ConfigCore.getBooleanParameterOrDefaultValue(ParameterCore.ASYNCHRONOUS_AUTOMATIC_EXPORT)) {
             TaskManager.addTask(new ExportDmsTask(this, process));
             Helper.setMessage(TaskSitter.isAutoRunningThreads() ? "DMSExportByThread" : "DMSExportThreadCreated",
                 process.getTitle());
             return false;
         } else {
             return startExport(process, (ExportDmsTask) null);
         }
     }
 
     /**
      * Performs a DMS export to a desired place. In addition, it accepts an
      * optional ExportDmsTask object. If that is passed in, the progress in it
      * will be updated during processing and occurring errors will be passed to
      * it to be visible in the task manager screen.
      *
      * @param process
      *            process to export
      * @param exportDmsTask
      *            ExportDmsTask object to submit progress updates and errors
      * @return false if an error condition was caught, true otherwise
      */
     public boolean startExport(Process process, ExportDmsTask exportDmsTask) {
         this.exportDmsTask = exportDmsTask;
         try {
             return startExport(process,
                 processService.readMetadataFile(process).getDigitalDocument());
         } catch (IOException | DAOException e) {
             if (Objects.nonNull(exportDmsTask)) {
                 exportDmsTask.setException(e);
                 logger.error(Helper.getTranslation(ERROR_EXPORT, process.getTitle()), e);
             } else {
                 Helper.setErrorMessage(ERROR_EXPORT, new Object[] {process.getTitle() }, logger, e);
             }
             return false;
         }
     }
 
     /**
      * Start export.
      *
      * @param process
      *            object
      * @param newFile
      *            DigitalDocument
      * @return boolean
      */
     private boolean startExport(Process process, LegacyMetsModsDigitalDocumentHelper newFile)
             throws IOException, DAOException {
 
         this.myPrefs = ServiceManager.getRulesetService().getPreferences(process.getRuleset());
 
         LegacyMetsModsDigitalDocumentHelper gdzfile = readDocument(process, newFile);
         if (Objects.isNull(gdzfile)) {
             return false;
         }
 
         boolean dataCopierResult = executeDataCopierProcess(gdzfile, process);
         if (!dataCopierResult) {
             return false;
         }
 
         trimAllMetadata(gdzfile.getDigitalDocument().getLogicalDocStruct());
 
         // validate metadata
         if (ConfigCore.getBooleanParameterOrDefaultValue(ParameterCore.USE_META_DATA_VALIDATION)
                 && !ServiceManager.getMetadataValidationService().validate(gdzfile, this.myPrefs, process)) {
             if (Objects.nonNull(exportDmsTask)) {
                 exportDmsTask.setException(new MetadataException("metadata validation failed", null));
             }
             return false;
         }
 
         return prepareExportLocation(process, gdzfile);
     }
 
     private boolean exportCompletedChildren(List<Process> children) throws DataException {
         for (Process child:children) {
             if (ProcessConverter.getCombinedProgressAsString(child, false).equals(COMPLETED) && !child.isExported()) {
                 if (!startExport(child)) {
                     return false;
                 }
             }
         }
         return true;
     }
 
     private boolean prepareExportLocation(Process process,
             LegacyMetsModsDigitalDocumentHelper gdzfile) throws IOException, DAOException {
 
         URI hotfolder = new File(process.getProject().getDmsImportRootPath()).toURI();
         String processTitle = Helper.getNormalizedTitle(process.getTitle());
         URI exportFolder = new File(hotfolder.getPath(), processTitle).toURI();
 
         // delete old export folder
         if (!fileService.delete(exportFolder)) {
             String message = Helper.getTranslation(ERROR_EXPORT, processTitle);
             String description = Helper.getTranslation(EXPORT_DIR_DELETE, exportFolder.getPath());
             Helper.setErrorMessage(message, description);
             if (Objects.nonNull(exportDmsTask)) {
                 exportDmsTask.setException(new ExportException(message + ": " + description));
             }
             return false;
         }
 
         fileService.createDirectory(hotfolder, processTitle);
 
         if (Objects.nonNull(exportDmsTask)) {
             exportDmsTask.setProgress(1);
         }
 
         return exportImagesAndMetsToDestinationUri(process, gdzfile, exportFolder);
     }
 
     private boolean exportImagesAndMetsToDestinationUri(Process process, LegacyMetsModsDigitalDocumentHelper gdzfile,
             URI destination) throws IOException, DAOException {
 
         if (exportWithImages) {
             try {
                 directoryDownload(process, destination);
             } catch (IOException | InterruptedException | RuntimeException | URISyntaxException e) {
                 if (Objects.nonNull(exportDmsTask)) {
                     exportDmsTask.setException(e);
                 } else {
                     Helper.setErrorMessage(ERROR_EXPORT, new Object[] {process.getTitle() }, logger, e);
                 }
                 return false;
             }
         }
 
         // export the file to the import folder
         return asyncExportWithImport(process, gdzfile, destination);
     }
 
     private boolean executeDataCopierProcess(LegacyMetsModsDigitalDocumentHelper gdzfile, Process process) {
         try {
             String rules = ConfigCore.getParameter(ParameterCore.COPY_DATA_ON_EXPORT);
             if (Objects.nonNull(rules) && !executeDataCopierProcess(gdzfile, process, rules)) {
                 return false;
             }
         } catch (NoSuchElementException e) {
             logger.catching(Level.TRACE, e);
             // no configuration simply means here is nothing to do
         }
         return true;
     }
 
     private boolean executeDataCopierProcess(LegacyMetsModsDigitalDocumentHelper gdzfile, Process process,
             String rules) {
         try {
             new DataCopier(rules).process(new CopierData(gdzfile, process));
         } catch (ConfigurationException e) {
             if (Objects.nonNull(exportDmsTask)) {
                 exportDmsTask.setException(e);
             } else {
                 Helper.setErrorMessage("dataCopier.syntaxError", e.getMessage(), logger, e);
                 return false;
             }
         }
         return true;
     }
 
     private LegacyMetsModsDigitalDocumentHelper readDocument(Process process, LegacyMetsModsDigitalDocumentHelper newFile) {
         LegacyMetsModsDigitalDocumentHelper gdzfile;
         try {
             gdzfile = new LegacyMetsModsDigitalDocumentHelper(this.myPrefs.getRuleset());
             gdzfile.setDigitalDocument(newFile);
             return gdzfile;
         } catch (RuntimeException e) {
             if (Objects.nonNull(exportDmsTask)) {
                 exportDmsTask.setException(e);
                 logger.error(Helper.getTranslation(ERROR_EXPORT, process.getTitle()), e);
             } else {
                 Helper.setErrorMessage(ERROR_EXPORT, new Object[] {process.getTitle() }, logger, e);
             }
             return null;
         }
     }
 
     private boolean asyncExportWithImport(Process process, LegacyMetsModsDigitalDocumentHelper gdzfile, URI userHome)
             throws IOException, DAOException {
 
         String atsPpnBand = Helper.getNormalizedTitle(process.getTitle());
         if (Objects.nonNull(exportDmsTask)) {
             exportDmsTask.setWorkDetail(atsPpnBand + ".xml");
         }
         boolean metsFileWrittenSuccesful = writeMetsFile(process, fileService.createResource(userHome,
                 File.separator + atsPpnBand + ".xml"), gdzfile);
 
         if (Objects.nonNull(exportDmsTask)) {
             exportDmsTask.setProgress(100);
         }
         return metsFileWrittenSuccesful;
     }
 
     /**
      * Get exportDmsTask.
      *
      * @return value of exportDmsTask
      */
     public EmptyTask getExportDmsTask() {
         return exportDmsTask;
     }
 
     /**
      * Get workflowTask.
      *
      * @return value of workFlowTask
      */
     public Task getWorkflowTask() {
         return workFlowTask;
     }
 
     /**
      * Set workflowTask.
      *
      * @param workFlowTask
      *              the workflow stask associated with the export
      */
     public void setWorkflowTask(Task workFlowTask) {
         this.workFlowTask = workFlowTask;
     }
 
 
     /**
      * Setter method to pass in a task thread to whom progress and error messages
      * shall be reported.
      *
      * @param task
      *            task implementation
      */
     public void setExportDmsTask(EmptyTask task) {
         this.exportDmsTask = task;
     }
 
     /**
      * Run through all metadata and children of given docstruct to trim the strings
      * calls itself recursively.
      */
     private void trimAllMetadata(LegacyDocStructHelperInterface inStruct) {
         // trim all metadata values
         for (LegacyMetadataHelper md : inStruct.getAllMetadata()) {
             if (Objects.nonNull(md.getValue())) {
                 md.setStringValue(md.getValue().trim());
             }
         }
 
         // run through all children of docstruct
         for (LegacyDocStructHelperInterface child : inStruct.getAllChildren()) {
             trimAllMetadata(child);
         }
     }
 
     /**
      * Download image.
      *
      * @param process
      *            object
      * @param userHome
      *            File
      * @param atsPpnBand
      *            String
      * @param ordnerEndung
      *            String
      */
     public void imageDownload(Process process, URI userHome, String atsPpnBand, final String ordnerEndung)
             throws IOException {
         // determine the source folder
         URI tifOrdner = processService.getImagesTifDirectory(true, process.getId(),
             process.getTitle(), process.getProcessBaseUri());
 
         // copy the source folder to the destination folder
         if (fileService.fileExist(tifOrdner) && !fileService.getSubUris(tifOrdner).isEmpty()) {
             URI zielTif = userHome.resolve(atsPpnBand + ordnerEndung + "/");
 
             // with Agora import simply create the folder
             if (!fileService.fileExist(zielTif)) {
                 fileService.createDirectory(userHome, atsPpnBand + ordnerEndung);
             }
 
             if (Objects.nonNull(exportDmsTask)) {
                 exportDmsTask.setWorkDetail(null);
             }
         }
     }
 
     /**
      * Starts copying all directories configured as export folder.
      *
      * @param process
      *            object
      * @param destination
      *            the destination directory
      * @throws InterruptedException
      *             if the user clicked stop on the thread running the export DMS
      *             task
      *
      */
     private void directoryDownload(Process process, URI destination) throws IOException, InterruptedException, URISyntaxException {
         Collection<Subfolder> processDirs = process.getProject().getFolders().parallelStream()
                 .filter(Folder::isCopyFolder).map(folder -> new Subfolder(process, folder))
                 .collect(Collectors.toList());
         VariableReplacer variableReplacer = new VariableReplacer(null, process, null);
 
         String uriToDestination = destination.toString();
         if (!uriToDestination.endsWith("/")) {
             uriToDestination = uriToDestination.concat("/");
         }
         for (Subfolder processDir : processDirs) {
             URI dstDir = new URI(uriToDestination
                     + variableReplacer.replace(processDir.getFolder().getRelativePath()));
             fileService.createDirectories(dstDir);
 
             Collection<URI> srcs = processDir.listContents().values();
             int progress = 0;
             for (URI src : srcs) {
                 if (Objects.nonNull(exportDmsTask)) {
                     exportDmsTask.setWorkDetail(fileService.getFileName(src));
                 }
                 fileService.copyFileToDirectory(src, dstDir);
                 if (Objects.nonNull(exportDmsTask)) {
                     exportDmsTask.setProgress((int) ((progress++ + 1) * 98d / processDirs.size() / srcs.size() + 1));
                     if (exportDmsTask.isInterrupted()) {
                         throw new InterruptedException();
                     }
                 }
             }
         }
     }
 }