Coverage Summary for Class: UploadFileDialog (org.kitodo.production.forms.dataeditor)

Class Method, % Line, %
UploadFileDialog 6,7% (2/30) 5,4% (9/168)
UploadFileDialog$1 0% (0/1) 0% (0/1)
Total 6,5% (2/31) 5,3% (9/169)


 /*
  * (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.production.forms.dataeditor;
 
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.URI;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
 import javax.faces.model.SelectItem;
 
 import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.kitodo.api.dataformat.LogicalDivision;
 import org.kitodo.api.dataformat.MediaVariant;
 import org.kitodo.api.dataformat.PhysicalDivision;
 import org.kitodo.api.dataformat.View;
 import org.kitodo.config.ConfigCore;
 import org.kitodo.config.enums.ParameterCore;
 import org.kitodo.data.database.beans.Folder;
 import org.kitodo.exceptions.InvalidImagesException;
 import org.kitodo.exceptions.MediaNotFoundException;
 import org.kitodo.exceptions.NoSuchMetadataFieldException;
 import org.kitodo.production.enums.GenerationMode;
 import org.kitodo.production.helper.Helper;
 import org.kitodo.production.helper.VariableReplacer;
 import org.kitodo.production.helper.tasks.EmptyTask;
 import org.kitodo.production.helper.tasks.TaskManager;
 import org.kitodo.production.helper.tasks.TaskState;
 import org.kitodo.production.metadata.InsertionPosition;
 import org.kitodo.production.metadata.MetadataEditor;
 import org.kitodo.production.model.Subfolder;
 import org.kitodo.production.services.ServiceManager;
 import org.kitodo.production.services.file.SubfolderFactoryService;
 import org.kitodo.production.services.image.ImageGenerator;
 import org.kitodo.production.thread.TaskImageGeneratorThread;
 import org.primefaces.PrimeFaces;
 import org.primefaces.event.FileUploadEvent;
 import org.primefaces.model.TreeNode;
 import org.primefaces.model.file.UploadedFile;
 
 public class UploadFileDialog {
     private static final Logger logger = LogManager.getLogger(UploadFileDialog.class);
 
     private final DataEditorForm dataEditor;
     private UploadedFile file;
     private String mimeType;
     private String fileExtension;
     private String use;
     private URI sourceFolderURI;
     private List<SelectItem> possiblePositions = new ArrayList<>();
     private InsertionPosition selectedPosition;
     private Folder sourceFolder;
     private final List<Folder> contentFolders = new ArrayList<>();
     private MediaVariant mediaVariant;
     private int indexSelectedMedia;
     private LogicalDivision parent;
     private URI uploadFileUri;
     private Subfolder generatorSource;
     private final int fileLimit = ConfigCore.getIntParameter(ParameterCore.METS_EDITOR_MAX_UPLOADED_MEDIA);
     private List<Pair<PhysicalDivision, LogicalDivision>> selectedMedia = new LinkedList<>();
     private Integer progress;
     private List<EmptyTask> generateMediaTasks = new ArrayList<>();
     private final List<TaskState> taskBlockedStates = Arrays.asList(TaskState.CRASHED, TaskState.STOPPED, TaskState.STOPPING);
 
     /**
      * Constructor.
      *
      * @param dataEditor Instance of DataEditorForm where this instance of UploadFileDialog was created.
      */
     UploadFileDialog(DataEditorForm dataEditor) {
         this.dataEditor = dataEditor;
     }
 
     /**
      * Get fileExtension.
      *
      * @return value of fileExtension
      */
     public String getFileExtension() {
         return fileExtension;
     }
 
     /**
      * Set fileExtension.
      *
      * @param fileExtension as java.lang.String
      */
     public void setFileExtension(String fileExtension) {
         this.fileExtension = fileExtension;
     }
 
     /**
      * Get fileLimit.
      *
      * @return value of fileLimit
      */
     public int getFileLimit() {
         return fileLimit;
     }
 
     /**
      * Get file.
      *
      * @return value of file
      */
     public UploadedFile getFile() {
         return file;
     }
 
     /**
      * Set file.
      *
      * @param file as org.primefaces.model.UploadedFile
      */
     public void setFile(UploadedFile file) {
         this.file = file;
     }
 
     /**
      * Get possiblePositions.
      *
      * @return value of possiblePositions
      */
     public List<SelectItem> getPossiblePositions() {
         return possiblePositions;
     }
 
     /**
      * Set possiblePositions.
      *
      * @param possiblePositions as java.util.List of SelectItem
      */
     public void setPossiblePositions(List<SelectItem> possiblePositions) {
         this.possiblePositions = possiblePositions;
     }
 
     /**
      * Get selectedPosition.
      *
      * @return value of selectedPosition
      */
     public InsertionPosition getSelectedPosition() {
         return selectedPosition;
     }
 
     /**
      * Set selectedPosition.
      *
      * @param selectedPosition as org.kitodo.production.metadata.InsertionPosition
      */
     public void setSelectedPosition(InsertionPosition selectedPosition) {
         this.selectedPosition = selectedPosition;
     }
 
     /**
      * Get progress.
      *
      * @return value of progress
      */
     public int getProgress() throws NoSuchMetadataFieldException, InvalidImagesException, MediaNotFoundException {
         if (generateMediaTasks.stream().anyMatch(emptyTask -> taskBlockedStates.contains(emptyTask.getTaskState()))) {
             PrimeFaces.current().executeScript("PF('progressBar').cancel();");
             updateWorkpiece();
         } else {
             progress = updateProgress();
         }
         return progress;
     }
 
     /**
      * Set progress.
      *
      * @param progress as int
      */
     public void setProgress(Integer progress) {
         this.progress = progress;
     }
 
     private Integer updateProgress() {
         if (!generateMediaTasks.isEmpty() && progress != 100) {
             return generateMediaTasks.stream().mapToInt(EmptyTask::getProgress).sum() / generateMediaTasks.size();
         } else {
             return progress;
         }
     }
 
     private MediaVariant getMediaVariant() {
         MediaVariant mediaVariant = new MediaVariant();
         mediaVariant.setMimeType(mimeType);
         mediaVariant.setUse(use);
         return mediaVariant;
     }
 
     private String getPhysicalDivType() {
         if (mimeType.contains("image")) {
             return PhysicalDivision.TYPE_PAGE;
         }
         if (mimeType.contains("audio")) {
             return PhysicalDivision.TYPE_TRACK;
         }
         return PhysicalDivision.TYPE_OTHER;
     }
 
     private boolean setUpFolders() {
         VariableReplacer variableReplacer = new VariableReplacer(null, dataEditor.getProcess(), null);
         sourceFolder = dataEditor.getProcess().getProject().getGeneratorSource();
         Folder mediaView = dataEditor.getProcess().getProject().getMediaView();
         Folder preview = dataEditor.getProcess().getProject().getPreview();
 
         if (Objects.isNull(sourceFolder) || Objects.isNull(mediaView) || Objects.isNull(preview)) {
             return false;
         }
 
         sourceFolder.setPath(variableReplacer.replace(sourceFolder.getRelativePath()));
         mediaView.setPath(variableReplacer.replace(mediaView.getRelativePath()));
         preview.setPath(variableReplacer.replace(preview.getRelativePath()));
 
         if (folderExists(sourceFolder) && folderExists(mediaView) && folderExists(preview)) {
             sourceFolderURI = getFolderURI(sourceFolder);
             contentFolders.add(mediaView);
             contentFolders.add(preview);
             return true;
         }
         return false;
     }
 
     private void sortViews(List<View> views) {
         views.sort(Comparator.comparing(v -> FilenameUtils.getBaseName(
                 v.getPhysicalDivision().getMediaFiles().entrySet().iterator().next().getValue().getPath())));
     }
 
     private boolean folderExists(Folder folder) {
         URI folderURI = getFolderURI(folder);
         if (!ServiceManager.getFileService().fileExist(folderURI)) {
             Helper.setErrorMessage("errorDirectoryNotFound", new Object[]{folderURI});
             return false;
         }
         return true;
     }
 
     private URI getFolderURI(Folder folder) {
         return Paths.get(ConfigCore.getKitodoDataDirectory(),
                 ServiceManager.getProcessService().getProcessDataDirectory(dataEditor.getProcess()).getPath(),
                 folder.getRelativePath()).toUri();
     }
 
     private void initPosition() {
         TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNode();
         if (Objects.nonNull(selectedLogicalNode)
                 && selectedLogicalNode.getData() instanceof StructureTreeNode) {
             StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData();
             if (structureTreeNode.getDataObject() instanceof View) {
                 if (Objects.nonNull(selectedLogicalNode.getParent())
                         && selectedLogicalNode.getParent().getData() instanceof StructureTreeNode
                         && Objects.nonNull(((StructureTreeNode) selectedLogicalNode.getParent().getData())
                         .getDataObject())
                         && ((StructureTreeNode) selectedLogicalNode.getParent().getData()).getDataObject()
                         instanceof LogicalDivision) {
                     parent =
                             (LogicalDivision) ((StructureTreeNode) selectedLogicalNode.getParent().getData())
                                     .getDataObject();
                     indexSelectedMedia = parent.getViews().indexOf((View)structureTreeNode.getDataObject());
 
                 }
             } else if (structureTreeNode.getDataObject() instanceof LogicalDivision) {
                 parent = (LogicalDivision) structureTreeNode.getDataObject();
             }
         }
     }
 
     private void preparePossiblePositions() {
         possiblePositions = new ArrayList<>();
         TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNode();
         if (Objects.nonNull(selectedLogicalNode)
                 && selectedLogicalNode.getData() instanceof StructureTreeNode) {
             StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData();
             if (structureTreeNode.getDataObject() instanceof View) {
                 possiblePositions.add(new SelectItem(InsertionPosition.BEFORE_CURRENT_ELEMENT,
                         Helper.getTranslation("dataEditor.position.beforeCurrentElement")));
                 possiblePositions.add(new SelectItem(InsertionPosition.AFTER_CURRENT_ELEMENT,
                         Helper.getTranslation("dataEditor.position.afterCurrentElement")));
             } else {
                 possiblePositions.add(new SelectItem(InsertionPosition.FIRST_CHILD_OF_CURRENT_ELEMENT,
                         Helper.getTranslation("dataEditor.position.asFirstChildOfCurrentElement")));
                 possiblePositions.add(new SelectItem(InsertionPosition.LAST_CHILD_OF_CURRENT_ELEMENT,
                         Helper.getTranslation("dataEditor.position.asLastChildOfCurrentElement")));
             }
         }
     }
 
     /**
      * Prepare popup dialog.
      */
     public void prepare() {
         progress = 0;
         generateMediaTasks = new ArrayList<>();
         selectedMedia = new LinkedList<>();
         if (!setUpFolders()) { return; }
         generatorSource = new Subfolder(dataEditor.getProcess(), sourceFolder);
         mimeType = sourceFolder.getMimeType();
         use = sourceFolder.getFileGroup();
         mediaVariant = getMediaVariant();
         fileExtension = generatorSource.getFileFormat().getExtension(false);
         preparePossiblePositions();
         initPosition();
         PrimeFaces.current().executeScript("PF('uploadFileDialog').show()");
     }
 
     /**
      * Upload media.
      *
      * @param event as FileUploadEvent
      */
     public void uploadMedia(FileUploadEvent event) {
         if (event.getFile() != null) {
 
             PhysicalDivision physicalDivision = MetadataEditor.addPhysicalDivision(getPhysicalDivType(),
                     dataEditor.getWorkpiece(), dataEditor.getWorkpiece().getPhysicalStructure(),
                     InsertionPosition.LAST_CHILD_OF_CURRENT_ELEMENT);
             uploadFileUri = sourceFolderURI.resolve(event.getFile().getFileName());
 
             //TODO: Find a better way to avoid overwriting an existing file
             if (ServiceManager.getFileService().fileExist(uploadFileUri)) {
                 String newFileName = ServiceManager.getFileService().getFileName(uploadFileUri)
                         + "_" + Helper.generateRandomString(3) + "." + fileExtension;
                 uploadFileUri = sourceFolderURI.resolve(newFileName);
             }
             physicalDivision.getMediaFiles().put(mediaVariant, uploadFileUri);
             //upload file in sourceFolder
             try (OutputStream outputStream = ServiceManager.getFileService().write(uploadFileUri)) {
                 IOUtils.copy(event.getFile().getInputStream(), outputStream);
             } catch (IOException e) {
                 Helper.setErrorMessage(e.getLocalizedMessage(), logger, e);
             }
             dataEditor.getUnsavedUploadedMedia().add(physicalDivision);
             selectedMedia.add(new ImmutablePair<>(physicalDivision, parent));
             PrimeFaces.current().executeScript("PF('notifications').renderMessage({'summary':'"
                     + Helper.getTranslation("mediaUploaded", event.getFile().getFileName())
                     + "','severity':'info'});");
         }
     }
 
     /**
      * Generate newly uploaded media.
      */
     public void generateNewUploadedMedia() {
         List<Subfolder> outputs = SubfolderFactoryService.createAll(dataEditor.getProcess(), contentFolders);
         ImageGenerator imageGenerator;
         if (generatorSource.listContents().isEmpty()) {
             imageGenerator = new ImageGenerator(generatorSource, GenerationMode.ALL, outputs);
         } else {
             imageGenerator = new ImageGenerator(generatorSource, GenerationMode.MISSING, outputs);
         }
         EmptyTask emptyTask = new TaskImageGeneratorThread(dataEditor.getProcess().getTitle(), imageGenerator);
         TaskManager.addTask(emptyTask);
         generateMediaTasks.add(emptyTask);
     }
 
     /**
      * Reset the progress bar after generating media is completed and update the workpiece.
      */
     public void updateWorkpiece() throws InvalidImagesException, NoSuchMetadataFieldException, MediaNotFoundException {
         generateMediaTasks.clear();
         addMediaToWorkpiece();
         refresh();
         if (progress != 100) {
             Helper.setErrorMessage("generateMediaFailed");
             PrimeFaces.current().executeScript("PF('uploadFileDialog').hide();");
             PrimeFaces.current().ajax().update("logicalTree", "metadataAccordion:logicalMetadataWrapperPanel",
                     "paginationForm:paginationWrapperPanel", "galleryWrapperPanel");
         } else {
             Helper.setMessage(Helper.getTranslation("uploadMediaCompleted"));
         }
         progress = 0;
     }
 
     private void addMediaToWorkpiece() throws InvalidImagesException, MediaNotFoundException {
         ServiceManager.getFileService().searchForMedia(dataEditor.getProcess(), dataEditor.getWorkpiece());
 
         List<View> views = selectedMedia.stream()
                 .map(v -> MetadataEditor.createUnrestrictedViewOn(v.getKey()))
                 .collect(Collectors.toList());
         sortViews(views);
         switch (selectedPosition) {
             case FIRST_CHILD_OF_CURRENT_ELEMENT:
                 parent.getViews().addAll(0, views);
                 break;
             case LAST_CHILD_OF_CURRENT_ELEMENT:
                 parent.getViews().addAll(views);
                 break;
             case AFTER_CURRENT_ELEMENT:
                 parent.getViews().addAll(indexSelectedMedia + 1, views);
                 break;
             case BEFORE_CURRENT_ELEMENT:
                 parent.getViews().addAll(indexSelectedMedia, views);
                 break;
             default:
                 throw new IllegalArgumentException("Position of new div element is not supported");
         }
     }
 
     /**
      * Refresh the metadataeditor after uploading media.
      */
     public void refresh() throws NoSuchMetadataFieldException {
         if (uploadFileUri != null && ServiceManager.getFileService().fileExist(uploadFileUri)) {
             selectedMedia.sort((Comparator.comparing(v -> FilenameUtils.getBaseName(
                     v.getKey().getMediaFiles().entrySet().iterator().next().getValue().getPath()))));
             dataEditor.getSelectedMedia().clear();
             dataEditor.getSelectedMedia().addAll(selectedMedia);
             dataEditor.getStructurePanel().show();
             dataEditor.getStructurePanel().preserve();
             dataEditor.refreshStructurePanel();
             dataEditor.getGalleryPanel().show();
             dataEditor.getStructurePanel().updateLogicalNodeSelection(
                     dataEditor.getGalleryPanel().getGalleryMediaContent(selectedMedia.get(selectedMedia.size() - 1).getKey()), parent);
             StructureTreeNode structureTreeNode = new StructureTreeNode(selectedMedia.get(selectedMedia.size() - 1).getKey().getLabel(), 
                     null, false, false,
                     MetadataEditor.createUnrestrictedViewOn(selectedMedia.get(selectedMedia.size() - 1).getKey()));
             dataEditor.switchStructure(structureTreeNode, false);
             dataEditor.getPaginationPanel().show();
             uploadFileUri = null;
         }
     }
 }