Coverage Summary for Class: CatalogConfigurationImporter (org.kitodo.production.helper)

Class Class, % Method, % Line, %
CatalogConfigurationImporter 0% (0/1) 0% (0/19) 0% (0/201)


 /*
  * (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.helper;
 
 import java.io.File;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
 import org.apache.commons.configuration.HierarchicalConfiguration;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.kitodo.api.externaldatamanagement.ImportConfigurationType;
 import org.kitodo.api.externaldatamanagement.SearchInterfaceType;
 import org.kitodo.api.schemaconverter.MetadataFormat;
 import org.kitodo.api.schemaconverter.MetadataFormatConversion;
 import org.kitodo.config.KitodoConfig;
 import org.kitodo.config.OPACConfig;
 import org.kitodo.data.database.beans.ImportConfiguration;
 import org.kitodo.data.database.beans.MappingFile;
 import org.kitodo.data.database.beans.SearchField;
 import org.kitodo.data.database.exceptions.DAOException;
 import org.kitodo.exceptions.InvalidPortException;
 import org.kitodo.exceptions.MandatoryParameterMissingException;
 import org.kitodo.exceptions.MappingFilesMissingException;
 import org.kitodo.exceptions.UndefinedMappingFileException;
 import org.kitodo.production.services.ServiceManager;
 
 /**
  * This class provides a way to convert catalog import configurations from existing 'kitodo_opac.xml'
  * configuration files into new 'ImportConfiguration' objects.
  */
 public class CatalogConfigurationImporter {
 
     private static final Logger logger = LogManager.getLogger(CatalogConfigurationImporter.class);
     private static final String FILE_UPLOAD_DEFAULT_POSTFIX = " - "
             + Helper.getTranslation("newProcess.fileUpload.heading");
     private static final String SEARCH_FIELD = "searchField";
     private static final String LABEL = "[@label]";
     private static final String VALUE = "[@value]";
     private static final String MAPPING_FILES = "mappingFiles";
 
     /**
      * Convert catalog configuration with title 'opacTitle' to new 'ImportConfiguration' object. Also creates
      * corresponding SearchField objects and assigns MappingFile objects according to original XML configuration.
      * @param catalogName title of catalog configuration in XML file
      * @throws DAOException when available MappingFile objects could not be loaded from database or new
      *                      ImportConfiguration object could not be saved to database
      * @throws UndefinedMappingFileException when XML catalog configuration contains mapping file for which no
      *                                       corresponding MappingFile instance can be found
      * @throws MappingFilesMissingException when XML catalog configuration does not contain mandatory 'mappingFiles'
      *                                       element.
      * @throws InvalidPortException when XML catalog configuration contains an invalid port value.
      */
     private void convertOpacConfig(String catalogName, List<String> currentConfigurations) throws DAOException,
             UndefinedMappingFileException, MappingFilesMissingException, MandatoryParameterMissingException,
             InvalidPortException, URISyntaxException, IOException {
         HierarchicalConfiguration opacConfiguration = OPACConfig.getCatalog(catalogName);
         String fileUploadTitle = catalogName + FILE_UPLOAD_DEFAULT_POSTFIX;
         if (OPACConfig.getFileUploadConfig(catalogName) && !currentConfigurations.contains(fileUploadTitle)) {
             createFileUploadConfiguration(catalogName, fileUploadTitle);
         }
         ImportConfiguration importConfiguration = null;
         if (Objects.nonNull(opacConfiguration)) {
             importConfiguration = new ImportConfiguration();
             importConfiguration.setTitle(catalogName);
             importConfiguration.setDescription(OPACConfig.getOPACDescription(catalogName));
             importConfiguration.setConfigurationType(ImportConfigurationType.OPAC_SEARCH.toString());
             importConfiguration.setReturnFormat(OPACConfig.getReturnFormat(catalogName).toUpperCase());
             setMetadataFormat(importConfiguration, catalogName);
             setParentMappingFile(importConfiguration);
             setSearchInterfaceType(importConfiguration, catalogName);
             setUrl(importConfiguration, catalogName);
             setItemFields(importConfiguration, catalogName);
             importConfiguration.setDefaultImportDepth(OPACConfig.getDefaultImportDepth(catalogName));
             setCredentials(importConfiguration, catalogName);
             importConfiguration.setIdPrefix(OPACConfig.getIdentifierPrefix(catalogName));
             importConfiguration.setParentElementTrimMode(OPACConfig.getParentIDTrimMode(catalogName));
             importConfiguration.setQueryDelimiter(OPACConfig.getQueryDelimiter(catalogName));
             importConfiguration.setPrestructuredImport(OPACConfig.isPrestructuredImport(catalogName));
             if (SearchInterfaceType.SRU.name().equals(importConfiguration.getInterfaceType())
                     || SearchInterfaceType.CUSTOM.name().equals(importConfiguration.getInterfaceType())) {
                 setSearchFields(importConfiguration, catalogName);
             }
             importConfiguration.setMappingFiles(getMappingFiles(importConfiguration));
             importConfiguration.setPrestructuredImport(OPACConfig.isPrestructuredImport(catalogName));
         }
         ServiceManager.getImportConfigurationService().saveToDatabase(importConfiguration);
     }
 
     private void setUrl(ImportConfiguration importConfiguration, String opacTitle)
             throws MandatoryParameterMissingException, InvalidPortException {
         importConfiguration.setScheme(OPACConfig.getScheme(opacTitle));
         importConfiguration.setHost(OPACConfig.getHost(opacTitle));
         importConfiguration.setPath(OPACConfig.getPath(opacTitle));
         importConfiguration.setPort(getPort(opacTitle));
     }
 
     private void setCredentials(ImportConfiguration importConfiguration, String opacTitle) {
         try {
             importConfiguration.setUsername(OPACConfig.getUsername(opacTitle));
             importConfiguration.setPassword(OPACConfig.getPassword(opacTitle));
         } catch (IllegalArgumentException e) {
             logger.info("No credentials configured for configuration '" + opacTitle + "'.");
         }
     }
 
     private void setSearchInterfaceType(ImportConfiguration importConfiguration, String opacTitle)
             throws MandatoryParameterMissingException {
         // use new "CUSTOM" type if SearchInterfaceType is null or could not be recognized
         SearchInterfaceType type = OPACConfig.getInterfaceType(opacTitle);
         if (Objects.nonNull(type) && Arrays.asList(SearchInterfaceType.values()).contains(type)) {
             importConfiguration.setInterfaceType(type.name());
         } else {
             importConfiguration.setInterfaceType(SearchInterfaceType.CUSTOM.name());
         }
         if (SearchInterfaceType.SRU.equals(type)) {
             importConfiguration.setSruVersion(OPACConfig.getSruVersion(opacTitle));
             importConfiguration.setSruRecordSchema(OPACConfig.getSruRecordSchema(opacTitle));
         } else if (SearchInterfaceType.OAI.equals(type)) {
             importConfiguration.setOaiMetadataPrefix(OPACConfig.getOaiMetadataPrefix(opacTitle));
         }
     }
 
     private void setMetadataFormat(ImportConfiguration importConfiguration, String opacTitle) {
         // set MetadataFormat to "OTHER" if configuration contains a value different from the options in the
         // "MetadataFormat.java" enum!
         String metadataFormat = OPACConfig.getMetadataFormat(opacTitle).toUpperCase();
         if (Arrays.stream(MetadataFormat.values()).map(MetadataFormat::name).collect(Collectors.toList())
                 .contains(metadataFormat)) {
             importConfiguration.setMetadataFormat(metadataFormat);
         } else {
             importConfiguration.setMetadataFormat(MetadataFormat.OTHER.name());
         }
         importConfiguration.setMetadataRecordIdXPath(MetadataFormat.getDefaultRecordIdXpath(metadataFormat));
         importConfiguration.setMetadataRecordTitleXPath(MetadataFormat.getDefaultRecordTitleXpath(metadataFormat));
     }
 
     private void setSearchFields(ImportConfiguration importConfiguration, String opacTitle) {
         importConfiguration.setSearchFields(getSearchFields(importConfiguration));
         for (SearchField searchField : importConfiguration.getSearchFields()) {
             if (OPACConfig.getDefaultSearchField(opacTitle).equals(searchField.getLabel())) {
                 importConfiguration.setDefaultSearchField(searchField);
                 break;
             }
         }
         for (SearchField searchField : importConfiguration.getSearchFields()) {
             if (OPACConfig.getIdentifierParameter(opacTitle).equals(searchField.getValue())) {
                 importConfiguration.setIdSearchField(searchField);
                 break;
             }
         }
     }
 
     private void setItemFields(ImportConfiguration importConfiguration, String opacTitle) {
         importConfiguration.setItemFieldXpath(OPACConfig.getExemplarFieldXPath(opacTitle));
         importConfiguration.setItemFieldOwnerSubPath(OPACConfig.getExemplarFieldOwnerXPath(opacTitle));
         importConfiguration.setItemFieldOwnerMetadata(OPACConfig.getExemplarFieldOwnerMetadata(opacTitle));
         importConfiguration.setItemFieldSignatureSubPath(OPACConfig.getExemplarFieldSignatureXPath(opacTitle));
         importConfiguration.setItemFieldSignatureMetadata(OPACConfig.getExemplarFieldSignatureMetadata(opacTitle));
     }
 
     private void createFileUploadConfiguration(String catalogTitle, String fileUploadConfigurationTitle)
             throws DAOException, UndefinedMappingFileException, MappingFilesMissingException, URISyntaxException,
             IOException {
         ImportConfiguration fileUploadConfiguration = new ImportConfiguration();
         fileUploadConfiguration.setConfigurationType(ImportConfigurationType.FILE_UPLOAD.name());
         fileUploadConfiguration.setTitle(catalogTitle);
         fileUploadConfiguration.setDescription(OPACConfig.getOPACDescription(catalogTitle));
         fileUploadConfiguration.setReturnFormat(OPACConfig.getReturnFormat(catalogTitle).toUpperCase());
         setMetadataFormat(fileUploadConfiguration, catalogTitle);
         setParentMappingFile(fileUploadConfiguration);
         fileUploadConfiguration.setMappingFiles(getMappingFiles(fileUploadConfiguration));
         // update title to include "File upload" postfix! (original title is required until here to load mapping files!)
         fileUploadConfiguration.setTitle(fileUploadConfigurationTitle);
         ServiceManager.getImportConfigurationService().saveToDatabase(fileUploadConfiguration);
     }
 
     private void setParentMappingFile(ImportConfiguration config) throws DAOException {
         for (MappingFile mappingFile : ServiceManager.getMappingFileService().getAll()) {
             if (mappingFile.getFile().equals(OPACConfig.getXsltMappingFileForParentInRecord(config.getTitle()))) {
                 config.setParentMappingFile(mappingFile);
                 break;
             }
         }
     }
 
     private List<SearchField> getSearchFields(ImportConfiguration configuration) {
         List<SearchField> searchFields = new LinkedList<>();
         for (HierarchicalConfiguration searchFieldConfig : OPACConfig.getSearchFields(configuration.getTitle())
                 .configurationsAt(SEARCH_FIELD)) {
             SearchField searchField = new SearchField();
             searchField.setLabel(searchFieldConfig.getString(LABEL));
             searchField.setValue(searchFieldConfig.getString(VALUE));
             searchField.setImportConfiguration(configuration);
             searchFields.add(searchField);
         }
         return searchFields;
     }
 
     private List<MappingFile> getMappingFiles(ImportConfiguration configuration) throws UndefinedMappingFileException,
             DAOException, MappingFilesMissingException, URISyntaxException, IOException {
         List<MappingFile> mappingFiles = new LinkedList<>();
         List<MappingFile> allMappingFiles = ServiceManager.getMappingFileService().getAll();
         try {
             OPACConfig.getCatalog(configuration.getTitle()).configurationAt(MAPPING_FILES);
             for (String filename : OPACConfig.getXsltMappingFiles(configuration.getTitle())) {
                 mappingFiles.add(getConfiguredMappingFile(allMappingFiles, filename, configuration));
             }
         } catch (IllegalArgumentException e) {
             logger.info("No 'mappingFiles' element found in catalog configuration '" + configuration.getTitle()
                     + "', trying to determine default mapping files.");
             String formatName = OPACConfig.getMetadataFormat(configuration.getTitle());
             MetadataFormat metadataFormat = MetadataFormat.getMetadataFormat(formatName);
             List<MetadataFormatConversion> defaultConversions = MetadataFormatConversion
                     .getDefaultConfigurationFileName(metadataFormat);
 
             if (Objects.nonNull(defaultConversions)) {
                 // add default metadata files to ImportConfiguration
                 URI xsltDir = Paths.get(KitodoConfig.getParameter("directory.xslt")).toUri();
                 for (MetadataFormatConversion metadataFormatConversion : defaultConversions) {
                     MappingFile mappingFile = null;
                     // Check, if default conversion has already been converted to MappingFile object
                     for (MappingFile currentFile : allMappingFiles) {
                         if (currentFile.getFile().equals(metadataFormatConversion.getFileName())) {
                             mappingFile = currentFile;
                             mappingFile.getImportConfigurations().add(configuration);
                             break;
                         }
                     }
                     // Create new MappingFile object if current default conversion has not yet been converted
                     if (Objects.isNull(mappingFile)) {
                         mappingFile = getMappingFile(xsltDir, metadataFormatConversion, formatName);
                         mappingFile.getImportConfigurations().add(configuration);
                     }
                     mappingFiles.add(mappingFile);
                 }
             } else {
                 throw new MappingFilesMissingException(formatName);
             }
         }
         return mappingFiles;
     }
 
     private MappingFile getConfiguredMappingFile(List<MappingFile> allMappingFiles, String filename,
                                                  ImportConfiguration configuration)
             throws UndefinedMappingFileException {
         MappingFile mappingFile = null;
         // Find mapping file object by filename
         for (MappingFile currentFile : allMappingFiles) {
             if (currentFile.getFile().equals(filename)) {
                 mappingFile = currentFile;
                 mappingFile.getImportConfigurations().add(configuration);
                 break;
             }
         }
         if (Objects.isNull(mappingFile)) {
             // Happens when user skips conversion of a mapping file used in the current import configuration!
             throw new UndefinedMappingFileException(filename);
         }
         return mappingFile;
     }
 
     private MappingFile getMappingFile(URI xsltDir, MetadataFormatConversion metadataFormatConversion,
                                              String formatName)
             throws IOException, URISyntaxException, DAOException {
         MappingFile mappingFile = new MappingFile();
         URI xsltFile = xsltDir.resolve(new URI(metadataFormatConversion.getFileName()));
         if (!new File(xsltFile).exists() && Objects.nonNull(metadataFormatConversion.getSource())) {
             downloadXSLTFile(metadataFormatConversion.getSource(), xsltFile);
         }
         mappingFile.setFile(metadataFormatConversion.getFileName());
         mappingFile.setTitle(metadataFormatConversion.getFileName());
         mappingFile.setPrestructuredImport(false);
         mappingFile.setInputMetadataFormat(formatName);
         mappingFile.setOutputMetadataFormat(metadataFormatConversion.getTargetFormat().name());
         mappingFile.setImportConfigurations(new LinkedList<>());
         ServiceManager.getMappingFileService().saveToDatabase(mappingFile);
         return mappingFile;
     }
 
     /**
      * Retrieve and return 'port' value of catalog with name 'catalogName' from 'kitodo_opac.xml' configuration file.
      *
      * @param catalogName name of catalog
      * @return port value as integer
      * @throws InvalidPortException if port value retrieved from 'kitodo_opac.xml' is not an integer between 0 and 65535
      */
     public static Integer getPort(String catalogName) throws InvalidPortException {
         try {
             String portString = OPACConfig.getPort(catalogName);
             if (StringUtils.isNotBlank(portString)) {
                 try {
                     int port = Integer.parseInt(portString);
                     if (port < 0 || port > 65535) {
                         throw new InvalidPortException(portString);
                     }
                     return port;
                 } catch (NumberFormatException e) {
                     throw new InvalidPortException(portString);
                 }
             }
         } catch (MandatoryParameterMissingException e) {
             // ignore exception because "port" is not mandatory
         }
         return null;
     }
 
     /**
      * Retrieve MappingFile objects from database for all catalog configurations in given list 'catalogs'.
      * @param catalogs list of catalog names as Strings
      * @return map containing mapping file names as keys and
      *         - corresponding MappingFile objects as values if it exists
      *         - null otherwise
      * @throws DAOException when MappingFile objects could not be loaded from database
      */
     public HashMap<String, MappingFile> getAllMappingFiles(List<String> catalogs) throws DAOException {
         HashMap<String, MappingFile> allMappingFiles = new HashMap<>();
         for (String catalogName : catalogs) {
             try {
                 List<String> mappingFileNames = OPACConfig.getXsltMappingFiles(catalogName);
                 String parentMappingFilename = OPACConfig.getXsltMappingFileForParentInRecord(catalogName);
                 if (Objects.nonNull(parentMappingFilename) && !mappingFileNames.contains(parentMappingFilename)) {
                     mappingFileNames.add(parentMappingFilename);
                 }
                 for (String xsltFilename : mappingFileNames) {
                     if (!allMappingFiles.containsKey(xsltFilename)) {
                         allMappingFiles.put(xsltFilename, null);
                         for (MappingFile mappingFile : ServiceManager.getMappingFileService().getAll()) {
                             if (mappingFile.getFile().equals(xsltFilename)) {
                                 allMappingFiles.put(xsltFilename, mappingFile);
                                 break;
                             }
                         }
                     }
                 }
             } catch (IllegalArgumentException e) {
                 logger.error("Unable to import OPAC configuration '" + catalogName + "' (" + e.getMessage() + ")");
             }
         }
         return allMappingFiles;
     }
 
     /**
      * Import all catalog configurations in given list 'catalogs' from configuration file 'kitodo_opac.xml' to new
      * ImportConfigurations. Return a map containing the results of the import process. The map contains the catalog
      * names as keys and potential error messages as values. Map entries with empty values mark successful catalog
      * configuration imports.
      *
      * @param catalogs list of catalog configurations to import from 'kitodo_opac.xml' by name
      * @return success map of catalog configuration import process
      * @throws DAOException when existing ImportConfigurations could not be retrieved from database
      */
     public HashMap<String, String> importCatalogConfigurations(List<String> catalogs) throws DAOException {
         HashMap<String, String> conversions = new HashMap<>();
         List<String> currentConfigurations = ServiceManager.getImportConfigurationService().getAll()
                 .stream().map(ImportConfiguration::getTitle).collect(Collectors.toList());
         for (String catalog : catalogs) {
             if (currentConfigurations.contains(catalog)) {
                 conversions.put(catalog, Helper.getTranslation("importConfig.migration.error.configurationExists"));
             } else {
                 try {
                     convertOpacConfig(catalog, currentConfigurations);
                     conversions.put(catalog, null);
                 } catch (UndefinedMappingFileException | MappingFilesMissingException
                          | MandatoryParameterMissingException | InvalidPortException | URISyntaxException
                          | IOException e) {
                     conversions.put(catalog, e.getMessage());
                 } catch (DAOException e) {
                     if (Objects.nonNull(e.getCause()) && Objects.nonNull(e.getCause().getCause())) {
                         conversions.put(catalog, e.getCause().getCause().getMessage());
                     } else {
                         conversions.put(catalog, e.getMessage());
                     }
                 }
             }
         }
         return conversions;
     }
 
     /**
      * Download XSLT file from given URL 'source' and save it to file located at given URI 'target'.
      * @param source URL of XSLT file to download.
      * @param target URI of location where downloaded files should be saved.
      * @throws IOException when file cannot be saved to provided location
      */
     public static void downloadXSLTFile(URL source, URI target) throws IOException {
         if (Objects.nonNull(source) && Objects.nonNull(target)) {
             FileUtils.copyURLToFile(source, new File(target));
         }
     }
 }