Java tutorial
/* * (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; import de.unigoettingen.sub.search.opac.ConfigOpac; import de.unigoettingen.sub.search.opac.ConfigOpacDoctype; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URI; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.stream.Collectors; import javax.enterprise.context.SessionScoped; import javax.faces.model.SelectItem; import javax.inject.Named; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.lang.SystemUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.goobi.production.cli.helper.CopyProcess; import org.goobi.production.plugin.PluginLoader; import org.goobi.production.plugin.catalogue.CataloguePlugin; import org.goobi.production.plugin.catalogue.Hit; import org.goobi.production.plugin.catalogue.QueryBuilder; import org.jdom.JDOMException; import org.kitodo.api.dataeditor.rulesetmanagement.RulesetManagementInterface; import org.kitodo.api.dataformat.IncludedStructuralElement; import org.kitodo.api.dataformat.Workpiece; import org.kitodo.config.ConfigCore; import org.kitodo.config.ConfigProject; import org.kitodo.config.DigitalCollection; import org.kitodo.config.enums.ParameterCore; import org.kitodo.data.database.beans.Process; import org.kitodo.data.database.beans.Project; import org.kitodo.data.database.beans.Property; import org.kitodo.data.database.beans.Task; import org.kitodo.data.database.beans.Template; import org.kitodo.data.database.enums.TaskEditType; import org.kitodo.data.database.enums.TaskStatus; import org.kitodo.data.exceptions.DataException; import org.kitodo.exceptions.ProcessCreationException; import org.kitodo.exceptions.ProcessGenerationException; import org.kitodo.production.enums.ObjectType; import org.kitodo.production.helper.Helper; import org.kitodo.production.helper.SelectItemList; import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyDocStructHelperInterface; import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyLogicalDocStructHelper; import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyLogicalDocStructTypeHelper; import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyMetadataHelper; import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyMetadataTypeHelper; import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyMetsModsDigitalDocumentHelper; import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyPrefsHelper; import org.kitodo.production.metadata.copier.CopierData; import org.kitodo.production.metadata.copier.DataCopier; import org.kitodo.production.process.ProcessGenerator; import org.kitodo.production.process.ProcessValidator; import org.kitodo.production.process.TiffHeaderGenerator; import org.kitodo.production.process.TitleGenerator; import org.kitodo.production.process.field.AdditionalField; import org.kitodo.production.services.ServiceManager; import org.kitodo.production.services.data.ProcessService; import org.kitodo.production.thread.TaskScriptThread; import org.omnifaces.util.Ajax; import org.primefaces.PrimeFaces; @Named("ProzesskopieForm") @SessionScoped public class ProzesskopieForm extends BaseForm { private static final Logger logger = LogManager.getLogger(ProzesskopieForm.class); private static final String OPAC_CONFIG = "configurationOPAC"; private static final String BOUND_BOOK = "boundbook"; private static final String FIRST_CHILD = "firstchild"; private static final String LIST_OF_CREATORS = "ListOfCreators"; private static final String DIRECTORY_SUFFIX = ConfigCore .getParameterOrDefaultValue(ParameterCore.DIRECTORY_SUFFIX); private String atstsl = ""; private Integer guessedImages = 0; private Process processForChoice; /** * The field hitlist holds some reference to the hitlist retrieved from a * library catalogue. The internals of this object are subject to the plugin * implementation and are not to be accessed directly. */ private Object hitlist; /** * The field hitlistPage holds the zero-based index of the page of the * hitlist currently showing. A negative value means that the hitlist is * hidden, otherwise it is showing the respective page. */ private long hitlistPage = -1; /** * The field hits holds the number of hits in the hitlist last retrieved * from a library catalogue. */ private long hits; /** * The field importCatalogue holds the catalogue plugin used to access the * library catalogue. */ private transient CataloguePlugin importCatalogue; private LegacyMetsModsDigitalDocumentHelper rdf; private String opacSuchfeld = "12"; private String opacSuchbegriff; private String opacKatalog; private final String processListPath = MessageFormat.format(REDIRECT_PATH, "processes"); private final String processFromTemplatePath = MessageFormat.format(REDIRECT_PATH, "processFromTemplate"); protected String docType; protected Template template = new Template(); protected Process prozessKopie = new Process(); protected Project project; protected boolean useOpac; protected boolean useTemplates; protected transient List<AdditionalField> additionalFields; protected transient Map<String, Boolean> standardFields; protected String tifDefinition; protected String titleDefinition; protected String tifHeaderImageDescription = ""; protected String tifHeaderDocumentName = ""; protected transient List<String> digitalCollections; protected transient List<String> possibleDigitalCollection; protected static final String INCOMPLETE_DATA = "errorDataIncomplete"; /** * Get atstsl. * * @return value of atstsl */ public String getAtstsl() { return atstsl; } /** * Get title definition. * * @return value of titleDefinition */ public String getTitleDefinition() { return titleDefinition; } /** * Prepare template and project for which new process will be created. * * @param templateId * id of template to query from database * @param projectId * id of project to query from database * * @return path to page with form */ public String prepare(int templateId, int projectId) { if (prepareProcess(templateId, projectId)) { return processFromTemplatePath; } return this.stayOnCurrentPage; } /** * Prepare new process which will be created. * * @param templateId * id of template to query from database * @param projectId * id of project to query from database * * @return true if process was prepared, otherwise false */ public boolean prepareProcess(int templateId, int projectId) { atstsl = ""; ProcessGenerator processGenerator = new ProcessGenerator(); try { boolean generated = processGenerator.generateProcess(templateId, projectId); if (generated) { this.prozessKopie = processGenerator.getGeneratedProcess(); this.project = processGenerator.getProject(); this.template = processGenerator.getTemplate(); clearValues(); readProjectConfigs(); this.rdf = null; this.digitalCollections = new ArrayList<>(); initializePossibleDigitalCollections(); return true; } } catch (ProcessGenerationException e) { Helper.setErrorMessage(e.getMessage(), logger, e); } return false; } /** * Get Process templates. * * @return list of SelectItem objects */ public List<SelectItem> getProcessesForChoiceList() { return SelectItemList.getProcessesForChoiceList(); } /** * The function evaluateOpac() is executed if a user clicks the command link * to start a catalogue search. It performs the search and loads the hit if * it is unique. Otherwise, it will cause a hit list to show up for the user * to select a hit. */ public void evaluateOpac() { long timeout = CataloguePlugin.getTimeout(); clearValues(); PrimeFaces.current().ajax().update("hitlistForm"); try { readProjectConfigs(); if (pluginAvailableFor(opacKatalog)) { String query = QueryBuilder.restrictToField(opacSuchfeld, opacSuchbegriff); query = QueryBuilder.appendAll(query, ConfigOpac.getRestrictionsForCatalogue(opacKatalog)); hitlist = importCatalogue.find(query, timeout); hits = importCatalogue.getNumberOfHits(hitlist, timeout); String message = MessageFormat.format(Helper.getTranslation("newProcess.catalogueSearch.results"), hits); switch ((int) Math.min(hits, Integer.MAX_VALUE)) { case 0: Helper.setErrorMessage(message); break; case 1: importHit(importCatalogue.getHit(hitlist, 0, timeout)); Helper.setMessage(message); break; default: hitlistPage = 0; // show first page of hitlist Helper.setMessage(message); PrimeFaces.current().executeScript("PF('hitlistDialog').show()"); break; } } else { Helper.setErrorMessage("ERROR: No suitable plugin available for OPAC '" + opacKatalog + "'"); } } catch (FileNotFoundException | RuntimeException e) { Helper.setErrorMessage(ERROR_READING, new Object[] { "OPAC " + opacKatalog }, logger, e); } } /** * Read project configs for display in GUI. */ protected void readProjectConfigs() { ConfigProject cp; try { cp = new ConfigProject(this.project.getTitle()); } catch (IOException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); return; } this.docType = cp.getDocType(); this.useOpac = cp.isUseOpac(); this.useTemplates = cp.isUseTemplates(); if (this.opacKatalog.equals("")) { this.opacKatalog = cp.getOpacCatalog(); } this.tifDefinition = cp.getTifDefinition(); this.titleDefinition = cp.getTitleDefinition(); this.standardFields.putAll(cp.getHiddenFields()); this.additionalFields = cp.getAdditionalFields(); } /** * The function pluginAvailableFor(catalogue) verifies that a plugin * suitable for accessing the library catalogue identified by the given * String is available in the global variable importCatalogue. If * importCatalogue is empty or the current plugin doesnt support the given * catalogue, the function will try to load a suitable plugin. Upon success * the preferences and the catalogue to use will be configured in the * plugin, otherwise an error message will be set to be shown. * * @param catalogue * identifier string for the catalogue that the plugin shall * support * @return whether a plugin is available in the global variable * importCatalogue */ private boolean pluginAvailableFor(String catalogue) { if (Objects.isNull(importCatalogue) || !importCatalogue.supportsCatalogue(catalogue)) { importCatalogue = PluginLoader.getCataloguePluginForCatalogue(catalogue); } if (Objects.isNull(importCatalogue)) { Helper.setErrorMessage("NoCataloguePluginForCatalogue", catalogue); return false; } else { importCatalogue .setPreferences(ServiceManager.getRulesetService().getPreferences(prozessKopie.getRuleset())); importCatalogue.useCatalogue(catalogue); return true; } } /** * Reset all configuration properties and fields. */ protected void clearValues() { if (Objects.isNull(this.opacKatalog)) { this.opacKatalog = ""; } this.standardFields = new HashMap<>(); this.standardFields.put("collections", true); this.standardFields.put("doctype", true); this.standardFields.put("regelsatz", true); this.standardFields.put("images", true); this.additionalFields = new ArrayList<>(); this.tifHeaderDocumentName = ""; this.tifHeaderImageDescription = ""; } /** * The method importHit() loads a hit into the display. * * @param hit * Hit to load */ protected void importHit(Hit hit) { rdf = hit.getFileformat(); docType = hit.getDocType(); fillFieldsFromMetadataFile(); applyCopyingRules(new CopierData(rdf, this.template)); atstsl = TitleGenerator.createAtstsl(hit.getTitle(), hit.getAuthors()); setEditActiveTabIndex(0); } /** * Creates a DataCopier with the given configuration, lets it process the * given data and wraps any errors to display in the front end. * * @param data * data to process */ private void applyCopyingRules(CopierData data) { String rules = ConfigCore.getParameter(ParameterCore.COPY_DATA_ON_CATALOGUE_QUERY); if (Objects.nonNull(rules)) { try { new DataCopier(rules).process(data); } catch (ConfigurationException e) { Helper.setErrorMessage("dataCopier.syntaxError", logger, e); } } } /** * die Eingabefelder fr die Eigenschaften mit Inhalten aus der RDF-Datei * fllen. */ private void fillFieldsFromMetadataFile() { if (Objects.nonNull(this.rdf)) { for (AdditionalField field : this.additionalFields) { if (field.isUghBinding() && field.showDependingOnDoctype()) { proceedField(field); String value = field.getValue(); if (Objects.nonNull(value) && !value.isEmpty()) { field.setValue(value.replace("&", "&")); } } } } } private void proceedField(AdditionalField field) { LegacyDocStructHelperInterface docStruct = getDocStruct(field); try { if (field.getMetadata().equals(LIST_OF_CREATORS)) { throw new UnsupportedOperationException("Dead code pending removal"); } else { // evaluate the content in normal fields LegacyMetadataTypeHelper mdt = LegacyPrefsHelper.getMetadataType( ServiceManager.getRulesetService().getPreferences(this.prozessKopie.getRuleset()), field.getMetadata()); LegacyMetadataHelper md = LegacyLogicalDocStructHelper.getMetadata(docStruct, mdt); if (Objects.nonNull(md)) { field.setValue(md.getValue()); md.setStringValue(field.getValue().replace("&", "&")); } } } catch (IllegalArgumentException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); } } private LegacyDocStructHelperInterface getDocStruct(AdditionalField field) { LegacyMetsModsDigitalDocumentHelper digitalDocument = this.rdf.getDigitalDocument(); LegacyDocStructHelperInterface docStruct = digitalDocument.getLogicalDocStruct(); if (field.getDocStruct().equals(FIRST_CHILD)) { docStruct = digitalDocument.getLogicalDocStruct().getAllChildren().get(0); } if (field.getDocStruct().equals(BOUND_BOOK)) { docStruct = digitalDocument.getPhysicalDocStruct(); } return docStruct; } /** * Auswahl des Prozesses auswerten. */ public String evaluateTemplateSelection() { readTemplateSelection(); try { this.rdf = ServiceManager.getProcessService().readMetadataAsTemplateFile(this.processForChoice); } catch (IOException | RuntimeException e) { Helper.setErrorMessage(ERROR_READING, new Object[] { "template-metadata" }, logger, e); } removeCollectionsForChildren(this.rdf, this.prozessKopie); return null; } protected void readTemplateSelection() { readTemplateWorkpieces(this.additionalFields, this.processForChoice); readTemplateTemplates(this.additionalFields, this.processForChoice); readTemplateProperties(this.digitalCollections, this.processForChoice); } protected void readTemplateWorkpieces(List<AdditionalField> additionalFields, Process processForChoice) { for (Property workpieceProperty : processForChoice.getWorkpieces()) { for (AdditionalField field : additionalFields) { if (field.getTitle().equals(workpieceProperty.getTitle())) { field.setValue(workpieceProperty.getValue()); } if (workpieceProperty.getTitle().equals("DocType") && !(this instanceof CopyProcess)) { this.docType = workpieceProperty.getValue(); } } } } protected void readTemplateTemplates(List<AdditionalField> additionalFields, Process processForChoice) { for (Property templateProperty : processForChoice.getTemplates()) { for (AdditionalField field : additionalFields) { if (field.getTitle().equals(templateProperty.getTitle())) { field.setValue(templateProperty.getValue()); } } } } private void readTemplateProperties(List<String> digitalCollections, Process processForChoice) { for (Property processProperty : processForChoice.getProperties()) { if (processProperty.getTitle().equals("digitalCollection")) { digitalCollections.add(processProperty.getValue()); } } } /** * If there is a first child, the collections are for it. */ protected void removeCollectionsForChildren(LegacyMetsModsDigitalDocumentHelper rdf, Process processCopy) { try { LegacyDocStructHelperInterface colStruct = rdf.getDigitalDocument().getLogicalDocStruct(); removeCollections(colStruct, processCopy); colStruct = colStruct.getAllChildren().get(0); removeCollections(colStruct, processCopy); } catch (RuntimeException e) { logger.debug("das Firstchild unterhalb des Topstructs konnte nicht ermittelt werden", e); } } /** * Create the process and save the meta-data. */ public String createNewProcess() { if (createProcess()) { return processListPath; } return this.stayOnCurrentPage; } /** * Create process. * * @return true if process was created, otherwise false */ public boolean createProcess() { if (!ProcessValidator.isContentValid(this.prozessKopie.getTitle(), this.additionalFields, this.getDigitalCollections(), this.standardFields, true)) { return false; } addProperties(); updateTasks(this.prozessKopie); try { this.prozessKopie.setSortHelperImages(this.guessedImages); ServiceManager.getProcessService().save(this.prozessKopie); } catch (DataException e) { Helper.setErrorMessage("errorCreating", new Object[] { ObjectType.PROCESS.getTranslationSingular() }, logger, e); return false; } if (!createProcessLocation()) { return false; } processRdfConfiguration(); try { ServiceManager.getProcessService().save(this.prozessKopie); } catch (DataException e) { Helper.setErrorMessage("errorCreating", new Object[] { ObjectType.PROCESS.getTranslationSingular() }, logger, e); return false; } return true; } private boolean createProcessLocation() { try { URI processBaseUri = ServiceManager.getFileService().createProcessLocation(this.prozessKopie); this.prozessKopie.setProcessBaseUri(processBaseUri); return true; } catch (IOException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); try { ServiceManager.getProcessService().remove(this.prozessKopie); } catch (DataException ex) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); } return false; } } /** * If there is an RDF configuration (for example, from the OPAC import, or * freshly created), then supplement these. */ private void processRdfConfiguration() { // create RDF config if there is none if (Objects.isNull(this.rdf)) { createNewFileformat(); } try { if (Objects.nonNull(this.rdf)) { insertLogicalDocStruct(); for (AdditionalField field : this.additionalFields) { if (field.isUghBinding() && field.showDependingOnDoctype()) { processAdditionalField(field); } } updateMetadata(); insertCollections(); insertImagePath(); } ServiceManager.getProcessService().readMetadataFile(this.prozessKopie); startTaskScriptThreads(); } catch (IOException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); } } private void processAdditionalField(AdditionalField field) { // which DocStruct LegacyDocStructHelperInterface tempStruct = this.rdf.getDigitalDocument().getLogicalDocStruct(); LegacyDocStructHelperInterface tempChild = null; String fieldDocStruct = field.getDocStruct(); if (fieldDocStruct.equals(FIRST_CHILD)) { try { tempStruct = this.rdf.getDigitalDocument().getLogicalDocStruct().getAllChildren().get(0); } catch (RuntimeException e) { Helper.setErrorMessage( e.getMessage() + " The first child below the top structure could not be determined!", logger, e); } } // if topstruct and first child should get the metadata if (!fieldDocStruct.equals(FIRST_CHILD) && fieldDocStruct.contains(FIRST_CHILD)) { try { tempChild = this.rdf.getDigitalDocument().getLogicalDocStruct().getAllChildren().get(0); } catch (RuntimeException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); } } if (fieldDocStruct.equals(BOUND_BOOK)) { tempStruct = this.rdf.getDigitalDocument().getPhysicalDocStruct(); } // which Metadata try { processAdditionalFieldWhichMetadata(field, tempStruct, tempChild); } catch (RuntimeException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); } } /** * Except for the authors, take all additional into the metadata. */ private void processAdditionalFieldWhichMetadata(AdditionalField field, LegacyDocStructHelperInterface tempStruct, LegacyDocStructHelperInterface tempChild) { if (!field.getMetadata().equals(LIST_OF_CREATORS)) { LegacyPrefsHelper prefs = ServiceManager.getRulesetService() .getPreferences(this.prozessKopie.getRuleset()); LegacyMetadataTypeHelper mdt = LegacyPrefsHelper.getMetadataType(prefs, field.getMetadata()); LegacyMetadataHelper metadata = LegacyLogicalDocStructHelper.getMetadata(tempStruct, mdt); if (Objects.nonNull(metadata)) { metadata.setStringValue(field.getValue()); } // if the topstruct and the first child should be given the // value if (Objects.nonNull(tempChild)) { metadata = LegacyLogicalDocStructHelper.getMetadata(tempChild, mdt); if (Objects.nonNull(metadata)) { metadata.setStringValue(field.getValue()); } } } } /** * There must be at least one non-anchor level doc struct, if missing, * insert logical doc structures until you reach it. */ private void insertLogicalDocStruct() { LegacyDocStructHelperInterface populizer = null; try { populizer = rdf.getDigitalDocument().getLogicalDocStruct(); if (Objects.nonNull(populizer.getAnchorClass()) && Objects.isNull(populizer.getAllChildren())) { LegacyLogicalDocStructTypeHelper docStructType = populizer.getDocStructType(); while (Objects.nonNull(docStructType.getAnchorClass())) { throw new UnsupportedOperationException("Dead code pending removal"); } } } catch (NullPointerException | IndexOutOfBoundsException e) { String name = Objects.nonNull(populizer) && Objects.nonNull(populizer.getDocStructType()) ? populizer.getDocStructType().getName() : null; Helper.setErrorMessage( "DocStrctType: " + name + " is configured as anchor but has no allowedchildtype.", logger, e); } } private void insertCollections() { LegacyDocStructHelperInterface colStruct = this.rdf.getDigitalDocument().getLogicalDocStruct(); if (Objects.nonNull(colStruct) && Objects.nonNull(colStruct.getAllChildren()) && !colStruct.getAllChildren().isEmpty()) { try { addCollections(colStruct); // falls ein erstes Kind vorhanden ist, sind die Collectionen // dafr colStruct = colStruct.getAllChildren().get(0); addCollections(colStruct); } catch (RuntimeException e) { Helper.setErrorMessage("The first child below the top structure could not be determined!", logger, e); } } } /** * Insert image path and delete any existing ones first. */ private void insertImagePath() throws IOException { LegacyMetsModsDigitalDocumentHelper digitalDocument = this.rdf.getDigitalDocument(); try { LegacyMetadataTypeHelper mdt = ProcessService.getMetadataType(this.prozessKopie, "pathimagefiles"); List<? extends LegacyMetadataHelper> allImagePaths = digitalDocument.getPhysicalDocStruct() .getAllMetadataByType(mdt); if (Objects.nonNull(allImagePaths)) { for (LegacyMetadataHelper metadata : allImagePaths) { digitalDocument.getPhysicalDocStruct().getAllMetadata().remove(metadata); } } LegacyMetadataHelper newMetadata = new LegacyMetadataHelper(mdt); String path = ServiceManager.getFileService().getImagesDirectory(this.prozessKopie) + this.prozessKopie.getTitle().trim() + "_" + DIRECTORY_SUFFIX; if (SystemUtils.IS_OS_WINDOWS) { newMetadata.setStringValue("file:/" + path); } else { newMetadata.setStringValue("file://" + path); } digitalDocument.getPhysicalDocStruct().addMetadata(newMetadata); // write Rdf file ServiceManager.getFileService().writeMetadataFile(this.rdf, this.prozessKopie); } catch (IllegalArgumentException e) { Helper.setErrorMessage("UghHelperException", logger, e); } } protected void updateTasks(Process process) { for (Task task : process.getTasks()) { // always save date and user for each step task.setProcessingTime(process.getCreationDate()); task.setEditType(TaskEditType.AUTOMATIC); // only if its done, set edit start and end date if (task.getProcessingStatus() == TaskStatus.DONE) { task.setProcessingBegin(process.getCreationDate()); // this concerns steps, which are set as done right on creation // bearbeitungsbeginn is set to creation timestamp of process // because the creation of it is basically begin of work Date date = new Date(); task.setProcessingTime(date); task.setProcessingEnd(date); } } } /** * Metadata inheritance and enrichment. */ private void updateMetadata() { if (ConfigCore.getBooleanParameter(ParameterCore.USE_METADATA_ENRICHMENT)) { LegacyDocStructHelperInterface enricher = rdf.getDigitalDocument().getLogicalDocStruct(); Map<String, Map<String, LegacyMetadataHelper>> higherLevelMetadata = new HashMap<>(); while (Objects.nonNull(enricher.getAllChildren())) { // save higher level metadata for lower enrichment List<LegacyMetadataHelper> allMetadata = enricher.getAllMetadata(); if (Objects.isNull(allMetadata)) { allMetadata = Collections.emptyList(); } iterateOverAllMetadata(higherLevelMetadata, allMetadata); // enrich children with inherited metadata for (LegacyDocStructHelperInterface nextChild : enricher.getAllChildren()) { enricher = nextChild; iterateOverHigherLevelMetadata(enricher, higherLevelMetadata); } } } } private void iterateOverAllMetadata(Map<String, Map<String, LegacyMetadataHelper>> higherLevelMetadata, List<LegacyMetadataHelper> allMetadata) { for (LegacyMetadataHelper available : allMetadata) { String availableKey = available.getMetadataType().getName(); String availableValue = available.getValue(); Map<String, LegacyMetadataHelper> availableMetadata = higherLevelMetadata.containsKey(availableKey) ? higherLevelMetadata.get(availableKey) : new HashMap<>(); if (!availableMetadata.containsKey(availableValue)) { availableMetadata.put(availableValue, available); } higherLevelMetadata.put(availableKey, availableMetadata); } } private void iterateOverHigherLevelMetadata(LegacyDocStructHelperInterface enricher, Map<String, Map<String, LegacyMetadataHelper>> higherLevelMetadata) { for (Entry<String, Map<String, LegacyMetadataHelper>> availableHigherMetadata : higherLevelMetadata .entrySet()) { String enrichable = availableHigherMetadata.getKey(); if (!isAddable(enricher, enrichable)) { continue; } for (Entry<String, LegacyMetadataHelper> higherElement : availableHigherMetadata.getValue() .entrySet()) { List<LegacyMetadataHelper> amNotNull = enricher.getAllMetadata(); if (Objects.isNull(amNotNull)) { amNotNull = Collections.emptyList(); } boolean breakMiddle = false; for (LegacyMetadataHelper existentMetadata : amNotNull) { if (existentMetadata.getMetadataType().getName().equals(enrichable) && existentMetadata.getValue().equals(higherElement.getKey())) { breakMiddle = true; break; } } if (breakMiddle) { break; } else { enricher.addMetadata(higherElement.getValue()); } } } } private boolean isAddable(LegacyDocStructHelperInterface enricher, String enrichable) { boolean addable = false; List<LegacyMetadataTypeHelper> addableTypesNotNull = enricher.getAddableMetadataTypes(); if (Objects.isNull(addableTypesNotNull)) { addableTypesNotNull = Collections.emptyList(); } for (LegacyMetadataTypeHelper addableMetadata : addableTypesNotNull) { if (addableMetadata.getName().equals(enrichable)) { addable = true; break; } } return addable; } private void startTaskScriptThreads() { /* damit die Sortierung stimmt nochmal einlesen */ ServiceManager.getProcessService().refresh(this.prozessKopie); List<Task> tasks = this.prozessKopie.getTasks(); for (Task task : tasks) { if (task.getProcessingStatus() == TaskStatus.OPEN && task.isTypeAutomatic()) { TaskScriptThread thread = new TaskScriptThread(task); thread.start(); } } } private void addCollections(LegacyDocStructHelperInterface colStruct) { for (String s : this.digitalCollections) { try { LegacyMetadataHelper md = new LegacyMetadataHelper(LegacyPrefsHelper.getMetadataType( ServiceManager.getRulesetService().getPreferences(this.prozessKopie.getRuleset()), "singleDigCollection")); md.setStringValue(s); md.setDocStruct(colStruct); colStruct.addMetadata(md); } catch (IllegalArgumentException e) { Helper.setErrorMessage(e.getMessage(), logger, e); } } } /** * alle Kollektionen eines bergebenen DocStructs entfernen. */ protected void removeCollections(LegacyDocStructHelperInterface colStruct, Process process) { try { LegacyMetadataTypeHelper mdt = LegacyPrefsHelper.getMetadataType( ServiceManager.getRulesetService().getPreferences(process.getRuleset()), "singleDigCollection"); ArrayList<LegacyMetadataHelper> myCollections = new ArrayList<>(colStruct.getAllMetadataByType(mdt)); for (LegacyMetadataHelper md : myCollections) { colStruct.removeMetadata(md); } } catch (IllegalArgumentException e) { Helper.setErrorMessage(e.getMessage(), logger, e); } } /** * Creates a new file format. When a new process is created, an empty METS * file must be created for it. */ public void createNewFileformat() { RulesetManagementInterface ruleset = ServiceManager.getRulesetService() .getPreferences(this.prozessKopie.getRuleset()).getRuleset(); try { Workpiece workpiece = new Workpiece(); IncludedStructuralElement includedStructuralElement = workpiece.getRootElement(); ConfigOpacDoctype configOpacDoctype = ConfigOpac.getDoctypeByName(this.docType); if (Objects.nonNull(configOpacDoctype)) { // monograph if (!configOpacDoctype.isPeriodical() && !configOpacDoctype.isMultiVolume()) { workpiece.getRootElement().setType(configOpacDoctype.getRulesetType()); this.rdf = new LegacyMetsModsDigitalDocumentHelper(ruleset, workpiece); } else if (configOpacDoctype.isPeriodical()) { // journal includedStructuralElement.setType("Periodical"); addChild(includedStructuralElement, "PeriodicalVolume"); this.rdf = new LegacyMetsModsDigitalDocumentHelper(ruleset, workpiece); } else if (configOpacDoctype.isMultiVolume()) { // volume of a multi-volume publication includedStructuralElement.setType("MultiVolumeWork"); addChild(includedStructuralElement, "Volume"); this.rdf = new LegacyMetsModsDigitalDocumentHelper(ruleset, workpiece); } } if (this.docType.equals("volumerun")) { includedStructuralElement.setType("VolumeRun"); addChild(includedStructuralElement, "Record"); this.rdf = new LegacyMetsModsDigitalDocumentHelper(ruleset, workpiece); } } catch (FileNotFoundException e) { Helper.setErrorMessage(ERROR_READING, new Object[] { Helper.getTranslation(OPAC_CONFIG) }, logger, e); } } /** * Adds a child node to a part of the logical structure tree. * * @param includedStructuralElement * tree to add to * @param type * type of child to create */ private void addChild(IncludedStructuralElement includedStructuralElement, String type) { IncludedStructuralElement volume = new IncludedStructuralElement(); volume.setType(type); includedStructuralElement.getChildren().add(volume); } private void addProperties() { addAdditionalFields(this.additionalFields, this.prozessKopie); for (String col : digitalCollections) { ProcessGenerator.addPropertyForProcess(this.prozessKopie, "digitalCollection", col); } ProcessGenerator.addPropertyForWorkpiece(this.prozessKopie, "DocType", this.docType); ProcessGenerator.addPropertyForWorkpiece(this.prozessKopie, "TifHeaderImagedescription", this.tifHeaderImageDescription); ProcessGenerator.addPropertyForWorkpiece(this.prozessKopie, "TifHeaderDocumentname", this.tifHeaderDocumentName); ProcessGenerator.addPropertyForProcess(this.prozessKopie, "Template", this.template.getTitle()); ProcessGenerator.addPropertyForProcess(this.prozessKopie, "TemplateID", String.valueOf(this.template.getId())); } protected void addAdditionalFields(List<AdditionalField> additionalFields, Process process) { for (AdditionalField field : additionalFields) { if (field.showDependingOnDoctype()) { if (field.getFrom().equals("werk")) { ProcessGenerator.addPropertyForWorkpiece(process, field.getTitle(), field.getValue()); } if (field.getFrom().equals("vorlage")) { ProcessGenerator.addPropertyForTemplate(process, field.getTitle(), field.getValue()); } if (field.getFrom().equals("prozess")) { ProcessGenerator.addPropertyForProcess(process, field.getTitle(), field.getValue()); } } } } public String getDocType() { return this.docType; } /** * Set document type. * * @param docType * String */ public void setDocType(String docType) { if (!this.docType.equals(docType)) { this.docType = docType; if (Objects.nonNull(rdf)) { LegacyMetsModsDigitalDocumentHelper tmp = rdf; createNewFileformat(); if (rdf.getDigitalDocument().getLogicalDocStruct() .equals(tmp.getDigitalDocument().getLogicalDocStruct())) { rdf = tmp; } else { LegacyDocStructHelperInterface oldLogicalDocstruct = tmp.getDigitalDocument() .getLogicalDocStruct(); LegacyDocStructHelperInterface newLogicalDocstruct = rdf.getDigitalDocument() .getLogicalDocStruct(); // both have no children if (oldLogicalDocstruct.getAllChildren() == null && newLogicalDocstruct.getAllChildren() == null) { copyMetadata(oldLogicalDocstruct, newLogicalDocstruct); } else if (oldLogicalDocstruct.getAllChildren() != null && newLogicalDocstruct.getAllChildren() == null) { // old has a child, new has no child copyMetadata(oldLogicalDocstruct, newLogicalDocstruct); copyMetadata(oldLogicalDocstruct.getAllChildren().get(0), newLogicalDocstruct); } else if (oldLogicalDocstruct.getAllChildren() == null && newLogicalDocstruct.getAllChildren() != null) { // new has a child, but old not copyMetadata(oldLogicalDocstruct, newLogicalDocstruct); throw new UnsupportedOperationException("Dead code pending removal"); } else if (oldLogicalDocstruct.getAllChildren() != null && newLogicalDocstruct.getAllChildren() != null) { // both have children copyMetadata(oldLogicalDocstruct, newLogicalDocstruct); copyMetadata(oldLogicalDocstruct.getAllChildren().get(0), newLogicalDocstruct.getAllChildren().get(0)); } } fillFieldsFromMetadataFile(); } } } private void copyMetadata(LegacyDocStructHelperInterface oldDocStruct, LegacyDocStructHelperInterface newDocStruct) { if (Objects.nonNull(oldDocStruct.getAllMetadata())) { for (LegacyMetadataHelper md : oldDocStruct.getAllMetadata()) { newDocStruct.addMetadata(md); } } } /** * Get template. * * @return value of template */ public Template getTemplate() { return template; } /** * Set template. * * @param template * as Template object */ public void setTemplate(Template template) { this.template = template; } /** * Get process for choice list. * * @return process for choice list */ public Process getProcessForChoice() { return this.processForChoice; } /** * Set process for choice list. * * @param processForChoice * as Process object */ public void setProcessForChoice(Process processForChoice) { this.processForChoice = processForChoice; } public List<AdditionalField> getAdditionalFields() { return this.additionalFields; } /** * The method getVisibleAdditionalFields returns a list of visible * additional fields. * * @return list of AdditionalField */ public List<AdditionalField> getVisibleAdditionalFields() { return this.getAdditionalFields().stream().filter(AdditionalField::showDependingOnDoctype) .collect(Collectors.toList()); } /** * The method setAdditionalField() sets the value of an AdditionalField held * by a ProzesskopieForm object. * * @param key * the title of the AdditionalField whose value shall be modified * @param value * the new value for the AdditionalField * @param strict * throw a RuntimeException if the field is unknown * @throws ProcessCreationException * in case that no field with a matching title was found in the * ProzesskopieForm object */ public void setAdditionalField(String key, String value, boolean strict) { boolean unknownField = true; for (AdditionalField field : additionalFields) { if (key.equals(field.getTitle())) { field.setValue(value); unknownField = false; } } if (unknownField && strict) { throw new ProcessCreationException( "Couldnt set " + key + "? to " + value + "?: No such field in record."); } } public void setAdditionalFields(List<AdditionalField> additionalFields) { this.additionalFields = additionalFields; } /** * This is needed for GUI, render multiple select only if this is false if * this is true use the only choice. * * @return true or false */ public boolean isSingleChoiceCollection() { return getPossibleDigitalCollections().size() == 1; } /** * Get possible digital collections if single choice. * * @return possible digital collections if single choice */ public String getDigitalCollectionIfSingleChoice() { List<String> pdc = getPossibleDigitalCollections(); if (pdc.size() == 1) { return pdc.get(0); } else { return null; } } public List<String> getPossibleDigitalCollections() { return this.possibleDigitalCollection; } protected void initializePossibleDigitalCollections() { try { DigitalCollection.possibleDigitalCollectionsForProcess(this.prozessKopie.getProject()); } catch (JDOMException | IOException e) { Helper.setErrorMessage("Error while parsing digital collections", logger, e); } this.possibleDigitalCollection = DigitalCollection.getPossibleDigitalCollection(); this.digitalCollections = DigitalCollection.getDigitalCollections(); // if only one collection is possible take it directly if (isSingleChoiceCollection()) { this.digitalCollections.add(getDigitalCollectionIfSingleChoice()); } } /** * Get all OPAC catalogues. * * @return list of catalogues */ public List<String> getAllOpacCatalogues() { try { return ConfigOpac.getAllCatalogueTitles(); } catch (RuntimeException e) { Helper.setErrorMessage(ERROR_READING, new Object[] { Helper.getTranslation(OPAC_CONFIG) }, logger, e); return new ArrayList<>(); } } /** * Get all document types. * * @return list of ConfigOpacDoctype objects */ public List<ConfigOpacDoctype> getAllDoctypes() { try { return ConfigOpac.getAllDoctypes(); } catch (RuntimeException e) { Helper.setErrorMessage(ERROR_READING, new Object[] { Helper.getTranslation(OPAC_CONFIG) }, logger, e); return new ArrayList<>(); } } /** * Changed, so that on first request list gets set if there is only one * choice. * * @return list of digital collections */ public List<String> getDigitalCollections() { return this.digitalCollections; } public void setDigitalCollections(List<String> digitalCollections) { this.digitalCollections = digitalCollections; } public Map<String, Boolean> getStandardFields() { return this.standardFields; } public boolean isUseOpac() { return this.useOpac; } public boolean isUseTemplates() { return this.useTemplates; } public String getTifHeaderDocumentName() { return this.tifHeaderDocumentName; } public void setTifHeaderDocumentName(String tifHeaderDocumentName) { this.tifHeaderDocumentName = tifHeaderDocumentName; } public String getTifHeaderImageDescription() { return this.tifHeaderImageDescription; } public void setTifHeaderImageDescription(String tifHeaderImageDescription) { this.tifHeaderImageDescription = tifHeaderImageDescription; } public Process getProzessKopie() { return this.prozessKopie; } public void setProzessKopie(Process prozessKopie) { this.prozessKopie = prozessKopie; } public String getOpacSuchfeld() { return this.opacSuchfeld; } public void setOpacSuchfeld(String opacSuchfeld) { this.opacSuchfeld = opacSuchfeld; } public String getOpacKatalog() { return this.opacKatalog; } public void setOpacKatalog(String opacKatalog) { this.opacKatalog = opacKatalog; } public String getOpacSuchbegriff() { return this.opacSuchbegriff; } public void setOpacSuchbegriff(String opacSuchbegriff) { this.opacSuchbegriff = opacSuchbegriff; } /** * Generate process titles and other details. */ public void calculateProcessTitle() { TitleGenerator titleGenerator = new TitleGenerator(this.atstsl, this.additionalFields); try { String newTitle = titleGenerator.generateTitle(this.titleDefinition, null); this.prozessKopie.setTitle(newTitle); // atstsl is created in title generator and next used in tiff header generator this.atstsl = titleGenerator.getAtstsl(); } catch (ProcessGenerationException e) { Helper.setErrorMessage(e.getMessage(), logger, e); return; } calculateTiffHeader(); Ajax.update("editForm:processFromTemplateTabView:processDataEditGrid"); } /** * Calculate tiff header. */ public void calculateTiffHeader() { // document name is generally equal to process title this.tifHeaderDocumentName = this.prozessKopie.getTitle(); TiffHeaderGenerator tiffHeaderGenerator = new TiffHeaderGenerator(this.atstsl, this.additionalFields); try { this.tifHeaderImageDescription = tiffHeaderGenerator.generateTiffHeader(this.tifDefinition, this.docType); } catch (ProcessGenerationException e) { Helper.setErrorMessage(e.getMessage(), logger, e); } } /** * Set images guessed. * * @param imagesGuessed * the imagesGuessed to set */ public void setImagesGuessed(Integer imagesGuessed) { if (Objects.isNull(imagesGuessed)) { imagesGuessed = 0; } this.guessedImages = imagesGuessed; } /** * Get images guessed. * * @return the imagesGuessed */ public Integer getImagesGuessed() { return this.guessedImages; } /** * The function isCalendarButtonShowing tells whether the calendar button * shall show up or not as read-only property "calendarButtonShowing". * * @return whether the calendar button shall show */ public boolean isCalendarButtonShowing() { try { return ConfigOpac.getDoctypeByName(docType).isNewspaper(); } catch (NullPointerException e) { // may occur if user continues to interact with the page across a // restart of the servlet container return false; } catch (FileNotFoundException e) { Helper.setErrorMessage(ERROR_READING, new Object[] { Helper.getTranslation(OPAC_CONFIG) }, logger, e); return false; } } /** * Returns the representation of the file holding the document metadata in * memory. * * @return the metadata file in memory */ public LegacyMetsModsDigitalDocumentHelper getFileformat() { return rdf; } }