Coverage Summary for Class: DataEditorService (org.kitodo.production.services.dataeditor)

Class Class, % Method, % Line, %
DataEditorService 100% (1/1) 37,5% (6/16) 9,4% (11/117)


 /*
  * (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.services.dataeditor;
 
 import java.io.IOException;
 import java.net.URI;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
 import javax.faces.model.SelectItem;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.kitodo.api.Metadata;
 import org.kitodo.api.MetadataEntry;
 import org.kitodo.api.MetadataGroup;
 import org.kitodo.api.dataeditor.DataEditorInterface;
 import org.kitodo.api.dataeditor.rulesetmanagement.ComplexMetadataViewInterface;
 import org.kitodo.api.dataeditor.rulesetmanagement.MetadataViewInterface;
 import org.kitodo.api.dataeditor.rulesetmanagement.SimpleMetadataViewInterface;
 import org.kitodo.api.dataeditor.rulesetmanagement.StructuralElementViewInterface;
 import org.kitodo.api.dataformat.LogicalDivision;
 import org.kitodo.api.dataformat.View;
 import org.kitodo.config.ConfigCore;
 import org.kitodo.config.enums.ParameterCore;
 import org.kitodo.data.database.beans.Ruleset;
 import org.kitodo.exceptions.InvalidMetadataValueException;
 import org.kitodo.production.forms.createprocess.ProcessDetail;
 import org.kitodo.production.forms.createprocess.ProcessFieldedMetadata;
 import org.kitodo.production.forms.dataeditor.DataEditorForm;
 import org.kitodo.production.forms.dataeditor.StructureTreeNode;
 import org.kitodo.production.helper.Helper;
 import org.kitodo.serviceloader.KitodoServiceLoader;
 import org.primefaces.model.TreeNode;
 
 public class DataEditorService {
 
     private static final Logger logger = LogManager.getLogger(DataEditorService.class);
 
     /**
      * Reads the data of a given file in xml format. The format of that file
      * needs to be the corresponding to the one which is referenced by the data
      * editor module as data format module.
      *
      * @param xmlFileUri
      *            The path to the metadata file as URI.
      */
     public void readData(URI xmlFileUri) throws IOException {
         DataEditorInterface dataEditor = loadDataEditorModule();
         URI xsltFile = getXsltFileFromConfig();
         dataEditor.readData(xmlFileUri, xsltFile);
     }
 
     private DataEditorInterface loadDataEditorModule() {
         KitodoServiceLoader<DataEditorInterface> serviceLoader = new KitodoServiceLoader<>(DataEditorInterface.class);
         return serviceLoader.loadModule();
     }
 
     private URI getXsltFileFromConfig() {
         String path = getXsltFolder();
         String file = ConfigCore.getParameter(ParameterCore.XSLT_FILENAME_METADATA_TRANSFORMATION);
         return Paths.get(path + file).toUri();
     }
 
     private String getXsltFolder() {
         return ConfigCore.getParameter(ParameterCore.DIR_XSLT);
     }
 
     /**
      * Retrieve and return list of metadata keys that are used for displaying title information in the metadata editors
      * structure and gallery panels from the Kitodo configuration file.
      *
      * @return list of title metadata keys
      */
     public static List<String> getTitleKeys() {
         return Arrays.stream(ConfigCore.getParameter(ParameterCore.TITLE_KEYS, "").split(","))
                 .map(String::trim).collect(Collectors.toList());
     }
 
     /**
      * Retrieve and return title value from given IncludedStructuralElement.
      *
      * @param element IncludedStructuralElement for which the title value is returned.
      * @param metadataTitleKey as a String that its value will be displayed.
      * @return title value of given element
      */
     public static String getTitleValue(LogicalDivision element, String metadataTitleKey) {
         String[] metadataPath = metadataTitleKey.split("@");
         int lastIndex = metadataPath.length - 1;
         Collection<Metadata> metadata = element.getMetadata();
         for (int i = 0; i < lastIndex; i++) {
             final String metadataKey = metadataPath[i];
             metadata = metadata.stream()
                     .filter(currentMetadata -> Objects.equals(currentMetadata.getKey(), metadataKey))
                     .filter(MetadataGroup.class::isInstance).map(MetadataGroup.class::cast)
                     .flatMap(metadataGroup -> metadataGroup.getMetadata().stream())
                     .collect(Collectors.toList());
         }
         Optional<String> metadataTitle = metadata.stream()
                 .filter(currentMetadata -> Objects.equals(currentMetadata.getKey(), metadataPath[lastIndex]))
                 .filter(MetadataEntry.class::isInstance).map(MetadataEntry.class::cast)
                 .map(MetadataEntry::getValue)
                 .filter(value -> !value.isEmpty())
                 .findFirst();
         if (metadataTitle.isPresent()) {
             return metadataTitle.get();
         }
         return " - ";
     }
 
     /**
      * Determine and return which metadata can be added to a specific MetadataGroup.
      *
      * @param ruleset ruleset of the process
      * @param metadataNode TreeNode containing MetadataGroup to check
      * @return List of select items representing addable metadata types
      */
     public static List<SelectItem> getAddableMetadataForGroup(Ruleset ruleset, TreeNode metadataNode) {
         ProcessFieldedMetadata fieldedMetadata = ((ProcessFieldedMetadata) metadataNode.getData());
         ComplexMetadataViewInterface metadataView = fieldedMetadata.getMetadataView();
         List<SelectItem> addableMetadata = new ArrayList<>();
         for (MetadataViewInterface keyView : metadataView.getAddableMetadata(fieldedMetadata.getChildMetadata(),
                 fieldedMetadata.getAdditionallySelectedFields())) {
             addableMetadata.add(
                     new SelectItem(keyView.getId(), keyView.getLabel(),
                             keyView instanceof SimpleMetadataViewInterface
                                     ? ((SimpleMetadataViewInterface) keyView).getInputType().toString()
                                     : "dataTable"));
         }
         return sortMetadataList(addableMetadata, ruleset);
     }
 
     /**
      * Determine and return which metadata can be added to the currently selected IncludedStructuralElement.
      * @param dataEditor DataEditorForm instance used to determine addable metadata types
      * @param currentElement whether addable metadata should be determined for currently selected
      *                       IncludedStructuralElement or not (if "false", it is determined for a new
      *                       IncludedStructuralElement added by "AddDocStrucElementDialog"!)
      * @param metadataNodes TreeNodes containing the metadata already assigned to the current structure element
      * @param structureType type of the new structure to be added and for which addable metadata is to be determined
      * @return List of select items representing addable metadata types
      */
     public static List<SelectItem> getAddableMetadataForStructureElement(DataEditorForm dataEditor,
                                                                          boolean currentElement,
                                                                          List<TreeNode> metadataNodes,
                                                                          String structureType,
                                                                          boolean isLogicalStructure) {
         List<SelectItem> addableMetadata = new ArrayList<>();
         Collection<Metadata> existingMetadata = Collections.emptyList();
         StructuralElementViewInterface structureView;
         try {
             if (currentElement) {
                 structureView = getStructuralElementView(dataEditor);
                 existingMetadata = getExistingMetadataRows(metadataNodes);
             } else {
                 structureView = dataEditor.getRulesetManagement()
                         .getStructuralElementView(structureType,
                                 dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
             }
             Collection<String> additionalFields = isLogicalStructure ? dataEditor.getMetadataPanel()
                     .getLogicalMetadataTable().getAdditionallySelectedFields() : dataEditor.getMetadataPanel()
                     .getPhysicalMetadataTable().getAdditionallySelectedFields();
             if (Objects.nonNull(structureView)) {
                 addableMetadata = getAddableMetadataForStructureElement(structureView, existingMetadata,
                         additionalFields, dataEditor.getProcess().getRuleset());
             }
         } catch (InvalidMetadataValueException e) {
             Helper.setErrorMessage(e);
         }
         return addableMetadata;
     }
 
     /**
      * Determine and return list of metadata that can be added to currently selected structure element.
      *
      * @param dataEditor DataEditorForm instance used to determine list of addable metadata types
      * @return List of select items representing addable metadata types
      */
     public static List<SelectItem> getAddableMetadataForStructureElement(DataEditorForm dataEditor) {
         return getAddableMetadataForStructureElement(dataEditor,
                 true, dataEditor.getMetadataPanel().getLogicalMetadataRows().getChildren(), null, true);
     }
 
     /**
      * Determine and return which metadata can be added to the currently selected IncludedStructuralElement.
      * @param structureView StructureElementViewInterface corresponding to structure element currently selected
      * @param existingMetadata existing Metadata of the structureView
      * @param additionalFields additionally added Metadata of the structureView
      * @param ruleset ruleset
      * @return List of select items representing addable metadata types
      */
     public static List<SelectItem> getAddableMetadataForStructureElement(StructuralElementViewInterface structureView,
                                                                          Collection<Metadata> existingMetadata,
                                                                          Collection<String> additionalFields, Ruleset ruleset) {
         List<SelectItem> addableMetadata = new ArrayList<>();
         Collection<MetadataViewInterface> viewInterfaces = structureView
                 .getAddableMetadata(existingMetadata, additionalFields);
         for (MetadataViewInterface keyView : viewInterfaces) {
             addableMetadata.add(
                     new SelectItem(keyView.getId(), keyView.getLabel(),
                             keyView instanceof SimpleMetadataViewInterface
                                     ? ((SimpleMetadataViewInterface) keyView).getInputType().toString()
                                     : "dataTable"));
         }
         return sortMetadataList(addableMetadata, ruleset);
     }
 
     /**
      * Determine and return list of metadata that can be added to currently selected media unit.
      *
      * @param dataEditor DataEditorForm instance used to determine list of addable metadata types
      * @return List of select items representing addable metadata types
      */
     public static List<SelectItem> getAddableMetadataForMediaUnit(DataEditorForm dataEditor) {
         return getAddableMetadataForStructureElement(dataEditor,
                 true, dataEditor.getMetadataPanel().getPhysicalMetadataRows().getChildren(), null, false);
     }
 
     /**
      * Determine and return StructureElementViewInterface corresponding to structure element currently selected or to be
      * added via AddDocStructTypeDialog.
      *
      * @param dataEditor DataEditorForm instance used to determine StructureElementViewInterface
      * @return StructureElementViewInterface corresponding to structure element currently selected or to be added
      */
     public static StructuralElementViewInterface getStructuralElementView(DataEditorForm dataEditor) {
         Optional<LogicalDivision> selectedStructure = dataEditor.getSelectedStructure();
         if (selectedStructure.isPresent()) {
             return dataEditor.getRulesetManagement()
                     .getStructuralElementView(
                             selectedStructure.get().getType(),
                             dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
         }
 
         TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNode();
 
         if (Objects.isNull(selectedLogicalNode)) {
             throw new IllegalStateException("No logical node selected!");
         }
 
         if (!(selectedLogicalNode.getData() instanceof StructureTreeNode)) {
             String nodeClass = "unknown";
             if (Objects.nonNull(selectedLogicalNode.getData())) {
                 nodeClass = selectedLogicalNode.getData().getClass().getName();
             }
             throw new IllegalStateException("Selected logical node data has wrong type '" + nodeClass
                     + "'! ('StructureTreeNode' expected)");
         }
         StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData();
 
         Object dataObject = structureTreeNode.getDataObject();
 
         // data object is null for structures inside parent processes
         if (Objects.isNull(dataObject)) {
             return null;
         }
 
         if (dataObject instanceof View) {
             View view = (View) dataObject;
             if (Objects.isNull(view.getPhysicalDivision())) {
                 throw new IllegalStateException("View has no physical division assigned!");
             }
             return dataEditor.getRulesetManagement().getStructuralElementView(
                 view.getPhysicalDivision().getType(),
                     dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
         }
 
         // data object is a sibling process
         if (dataObject instanceof Process) {
             return null;
         }
         throw new IllegalStateException("Data object has unknown type '" + dataObject.getClass().getName() + "'!");
     }
 
     /**
      * Get existing Metadata in metadataTreeNodes.
      * @param metadataTreeNodes as a List of TreeNode
      * @return the existing metadata
      */
     public static Collection<Metadata> getExistingMetadataRows(List<TreeNode> metadataTreeNodes) throws InvalidMetadataValueException {
         Collection<Metadata> existingMetadataRows = new ArrayList<>();
 
         for (TreeNode metadataNode : metadataTreeNodes) {
             if (metadataNode.getData() instanceof ProcessDetail) {
                 try {
                     existingMetadataRows.addAll(((ProcessDetail) metadataNode.getData()).getMetadata(false));
                 } catch (NullPointerException e) {
                     logger.error(e);
                 }
             }
         }
         return existingMetadataRows;
     }
 
     /**
      * Sort a metadata list alphabetically if the 'orderMetadataByRuleset' parameter of the ruleset not set as true.
      * @param itemList as a List of SelectItem
      * @param ruleset as a Ruleset
      * @return itemList
      */
     public static List<SelectItem> sortMetadataList(List<SelectItem> itemList, Ruleset ruleset) {
         if (!(itemList.isEmpty() || ruleset.isOrderMetadataByRuleset())) {
             itemList.sort(Comparator.comparing(SelectItem::getLabel));
         }
         return itemList;
     }
 }