Skip to content

Commit

Permalink
Add list function for renaming media of multiple processes
Browse files Browse the repository at this point in the history
  • Loading branch information
solth committed Nov 14, 2023
1 parent 23235ae commit 2aac76e
Show file tree
Hide file tree
Showing 15 changed files with 395 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1182,4 +1182,11 @@ private int getProcessId(Object process) {
public FilterMenu getFilterMenu() {
return filterMenu;
}

/**
* Rename media files of all selected processes.
*/
public void renameMedia() {
ServiceManager.getFileService().renameMedia(getSelectedProcesses());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
Expand All @@ -33,6 +34,7 @@
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
Expand Down Expand Up @@ -64,11 +66,14 @@
import org.kitodo.production.helper.metadata.ImageHelper;
import org.kitodo.production.helper.metadata.legacytypeimplementations.LegacyMetsModsDigitalDocumentHelper;
import org.kitodo.production.helper.metadata.pagination.Paginator;
import org.kitodo.production.helper.tasks.TaskManager;
import org.kitodo.production.metadata.MetadataEditor;
import org.kitodo.production.metadata.MetadataLock;
import org.kitodo.production.model.Subfolder;
import org.kitodo.production.services.ServiceManager;
import org.kitodo.production.services.command.CommandService;
import org.kitodo.production.services.data.RulesetService;
import org.kitodo.production.thread.RenameMediaThread;
import org.kitodo.serviceloader.KitodoServiceLoader;

public class FileService {
Expand Down Expand Up @@ -1515,6 +1520,37 @@ public int renameMediaFiles(Process process, Workpiece workpiece, DualHashBidiMa
return numberOfRenamedMedia;
}

/**
* Rename media files of given processes.
* @param processes Processes whose media is renamed
*/
public void renameMedia(List<Process> processes) {
processes = lockAndSortProcessesForRenaming(processes);
TaskManager.addTask(new RenameMediaThread(processes));
}

private List<Process> lockAndSortProcessesForRenaming(List<Process> processes) {
processes.sort(Comparator.comparing(Process::getId));
List<Integer> lockedProcesses = new LinkedList<>();
for (Process process : processes) {
int processId = process.getId();
if (MetadataLock.isLocked(processId)) {
lockedProcesses.add(processId);
if (ConfigCore.getBooleanParameterOrDefaultValue(ParameterCore.ANONYMIZE)) {
logger.error("Unable to lock process " + processId + " for media renaming because it is currently "
+ "being worked on by another user");
} else {
User currentUser = MetadataLock.getLockUser(processId);
logger.error("Unable to lock process " + processId + " for media renaming because it is currently "
+ "being worked on by another user (" + currentUser.getFullName() + ")");
}
} else {
MetadataLock.setLocked(processId, ServiceManager.getUserService().getCurrentUser());
}
}
return processes.stream().filter(p -> !lockedProcesses.contains(p.getId())).collect(Collectors.toList());
}

/**
* Revert renaming of media files when the user leaves the metadata editor without saving. This method uses a
* provided map object to rename media files identified by the map entries values to the corresponding map entries
Expand All @@ -1525,6 +1561,7 @@ public int renameMediaFiles(Process process, Workpiece workpiece, DualHashBidiMa
*/
public void revertRenaming(BidiMap<URI, URI> filenameMappings, Workpiece workpiece) {
// revert media variant URIs for all media files in workpiece to previous, original values
logger.info("Reverting to original media filenames of process " + workpiece.getId());
for (PhysicalDivision physicalDivision : workpiece
.getAllPhysicalDivisionChildrenFilteredByTypes(PhysicalDivision.TYPES)) {
for (Entry<MediaVariant, URI> mediaVariantURIEntry : physicalDivision.getMediaFiles().entrySet()) {
Expand All @@ -1536,8 +1573,14 @@ public void revertRenaming(BidiMap<URI, URI> filenameMappings, Workpiece workpie
try {
List<URI> tempUris = new LinkedList<>();
for (Entry<URI, URI> mapping : filenameMappings.entrySet()) {
tempUris.add(fileManagementModule.rename(mapping.getKey(), mapping.getValue().toString()
+ TEMP_EXTENSION));
if (mapping.getKey().toString().endsWith(TEMP_EXTENSION)) {
// if current URI has '.tmp' extension, directly revert to original name (without '.tmp' extension)
tempUris.add(fileManagementModule.rename(mapping.getKey(), mapping.getValue().toString()));
} else {
// rename to new filename with '.tmp' extension otherwise
tempUris.add(fileManagementModule.rename(mapping.getKey(), mapping.getValue().toString()
+ TEMP_EXTENSION));
}
}
for (URI tempUri : tempUris) {
fileManagementModule.rename(tempUri, StringUtils.removeEnd(tempUri.toString(), TEMP_EXTENSION));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* (c) Kitodo. Key to digital objects e. V. <[email protected]>
*
* 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.thread;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Objects;

import org.apache.commons.collections4.bidimap.DualHashBidiMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.kitodo.api.dataformat.Workpiece;
import org.kitodo.data.database.beans.Process;
import org.kitodo.production.helper.Helper;
import org.kitodo.production.helper.LocaleHelper;
import org.kitodo.production.helper.tasks.EmptyTask;
import org.kitodo.production.metadata.MetadataLock;
import org.kitodo.production.services.ServiceManager;

/**
* This class is used to rename media files of multiple processes in a separate thread whose progress can be monitored
* in the task manager.
*/
public class RenameMediaThread extends EmptyTask {

private static final Logger logger = LogManager.getLogger(RenameMediaThread.class);
private final List<Process> processes;
private static final String THREAD_NAME = "renameMediaThread";
private static final String ERRORS_OCCURRED_KEY = "errorsOccurredCheckLog";
private static final String PROCESSES = "processes";

public RenameMediaThread(List<Process> processes) {
super(processes.size() + " " + Helper.getString(LocaleHelper.getCurrentLocale(), PROCESSES));
this.processes = processes;
}

@Override
protected void setNameDetail(String detail) {
String localThreadName = Helper.getString(LocaleHelper.getCurrentLocale(), THREAD_NAME);
super.setName(localThreadName + ": " + detail);
}

/**
* Run method of this thread. Iterates over processes and renames all media files in each process using the regular
* "media renaming" functionality of the FileService.
*/
@Override
public void run() {
for (Process process : processes) {
int processId = process.getId();
URI metaXmlUri = ServiceManager.getProcessService().getMetadataFileUri(process);
DualHashBidiMap<URI, URI> renamingMap = new DualHashBidiMap<>();
Workpiece workpiece = null;
try {
workpiece = ServiceManager.getMetsService().loadWorkpiece(metaXmlUri);
int numberOfRenamedFiles = ServiceManager.getFileService().renameMediaFiles(process, workpiece,
renamingMap);
try (OutputStream out = ServiceManager.getFileService().write(metaXmlUri)) {
ServiceManager.getMetsService().save(workpiece, out);
logger.info("Renamed " + numberOfRenamedFiles + " media files for process " + process.getId());
}
} catch (IOException | URISyntaxException e) {
logger.error(e.getMessage());
String nameDetailMessage = processes.size()
+ " " + Helper.getString(LocaleHelper.getCurrentLocale(), PROCESSES)
+ " (" + Helper.getString(LocaleHelper.getCurrentLocale(), ERRORS_OCCURRED_KEY) + ")";
this.setNameDetail(nameDetailMessage);
if (Objects.nonNull(workpiece)) {
ServiceManager.getFileService().revertRenaming(renamingMap.inverseBidiMap(), workpiece);
}
}
MetadataLock.setFree(processId);
setProgress((100 / processes.size()) * (processes.indexOf(process) + 1));
}
setProgress(100);
}
}
1 change: 1 addition & 0 deletions Kitodo/src/main/resources/messages/errors_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ noUserInStep=Der Aufgabe {0} wurden keine Nutzer zugeordnet.

# O
errorOccurred=Es ist ein Fehler aufgetreten:
errorsOccurredCheckLog=Es sind Fehler aufgetreten. Bitte \u00FCberprf\u00FCfen Sie kitodo.log f\u00FCr zus\u00E4tzliche Details.

# P
errorParsingFile=Parsingfehler: verschiedene {0} in der Datei (''{1}'' & ''{2}'').
Expand Down
1 change: 1 addition & 0 deletions Kitodo/src/main/resources/messages/errors_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ noUserInStep=No user assigned to step {0}.

# O
errorOccurred=An error has occurred:
errorsOccurredCheckLog=Errors occurred. Please check kitodo.log for Details.

# P
errorParsingFile=Error parsing: various {0} in the file (''{1}'' & ''{2}'').
Expand Down
3 changes: 2 additions & 1 deletion Kitodo/src/main/resources/messages/messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ dataEditor.removeElement.noConsecutivePagesSelected=Strukturelemente k\u00F6nnen
dataEditor.selectMetadataTask=Aufgabe w\u00E4hlen
dataEditor.layoutSavedSuccessfullyTitle=Aktuelle Spaltenaufteilung erfolgreich gespeichert
dataEditor.layoutSavedSuccessfullyText=Ihre aktuellen Metadaten-Editor-Einstellungen wurden erfolgreich gespeichert! Sie werden f\u00FCr alle zuk\u00FCnftigen Aufgaben dieses Typs wiederverwendet.
dataEditor.renameMedia=Medien umbenennen
dataEditor.renamingMediaComplete=Das Umbenennen der Medien ist abgeschlossen
dataEditor.renamingMediaError=Beim Umbenennen der Medien ist ein Fehler aufgetreten
dataEditor.renamingMediaText={0} Mediendateien in {1} Ordnern wurden umbenannt. Bitte Speichern Sie den Vorgang. Andernfalls werden die Dateiumbennungen beim Schlie\u00DFen des Metadateneditors verworfen.
Expand Down Expand Up @@ -961,6 +960,7 @@ removePhysicalDivision=Physisches Strukturelement entfernen
removeRole=Rolle entfernen
removeUserFromGroup=Benutzer aus der Benutzergruppe l\u00F6schen
renameBatch=Batch umbenennen
renameMediaFiles=Medien umbenennen
requiredField=Mit * gekennzeichnete Felder sind Pflichtfelder
reset=Zur\u00FCcksetzen
resultPDF=Ergebnis-PDF
Expand Down Expand Up @@ -1281,6 +1281,7 @@ assignTask=Aufgabe zuweisen
overrideTask=Aufgabe \u00FCbernehmen
superviseTask=Aufgabe beobachten
renameMedia=Medien umbenennen
renameMediaThread=Medien umbenennen
resetWorkflow=Workflow zur\u00FCcksetzen
runKitodoScript=KitodoScript ausf\u00FChren

Expand Down
3 changes: 2 additions & 1 deletion Kitodo/src/main/resources/messages/messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ dataEditor.removeElement.noConsecutivePagesSelected=Select consecutive pages to
dataEditor.selectMetadataTask=Select task
dataEditor.layoutSavedSuccessfullyTitle=Current layout successfully saved
dataEditor.layoutSavedSuccessfullyText=Your current editor settings have been saved successfully and will be applied to all future tasks of the same type.
dataEditor.renameMedia=Rename media
dataEditor.renamingMediaComplete=Finished renaming media
dataEditor.renamingMediaError=An error occurred while renaming media files
dataEditor.renamingMediaText={0} media files in {1} folders have been renamed. Please click the 'Save' button to persist changes to the filenames. Otherwise the renaming will be reverted upon closing the editor.
Expand Down Expand Up @@ -962,6 +961,7 @@ removePhysicalDivision=Remove physical structure element
removeRole=Remove role
removeUserFromGroup=Delete user from group
renameBatch=Rename batch
renameMediaFiles=Rename media
requiredField=Fields marked with * are required
reset=Reset
resultPDF=Result PDF
Expand Down Expand Up @@ -1283,6 +1283,7 @@ overrideTask=Take on task
superviseTask=Watch task
resetWorkflow=Reset workflow
renameMedia=Rename media
renameMediaThread=Rename media
runKitodoScript=Execute KitodoScript

viewAllAuthorities=View all authorities
Expand Down
3 changes: 2 additions & 1 deletion Kitodo/src/main/resources/messages/messages_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ dataEditor.removeElement.noConsecutivePagesSelected=Los elementos estructurales
dataEditor.selectMetadataTask=Seleccionar la tarea
dataEditor.layoutSavedSuccessfullyTitle=La plantilla actual se guardó correctamente
dataEditor.layoutSavedSuccessfullyText=Su configuración actual del editor ha sido guardada con éxito y será aplicadad a todas las tareas futuras del mismo tipo.
dataEditor.renameMedia=Cambiar el nombre de los archivos de medios
dataEditor.renamingMediaComplete=El cambio de nombre de los medios ha finalizado
dataEditor.renamingMediaError=Se produjo un error al cambiar el nombre de los archivos multimedia
dataEditor.renamingMediaText=Se ha cambiado el nombre de {0} archivos de medios en {1} carpeta. Por favor, haga clic en el botón 'Guardar' para mantener los cambios en los nombres de archivo. De lo contrario, el cambio de nombre se revertirá al cerrar el editor.
Expand Down Expand Up @@ -951,6 +950,7 @@ removePhysicalDivision=Eliminar la posición de la estructura física
removeRole=Eliminar el rol
removeUserFromGroup=Eliminar un usuario del grupo de usuarios
renameBatch=Cambiar el nombre del lote
renameMediaFiles=Cambiar el nombre de los archivos de medios
requiredField=Los campos marcados con * son obligatorios
reset=Restablecer
resultPDF=Resultado PDF
Expand Down Expand Up @@ -1272,6 +1272,7 @@ overrideTask=Asumir la tarea
superviseTask=Observar la tarea
resetWorkflow=Restablecer el flujo de trabajo
renameMedia=Cambiar el nombre de los archivos multimedia
renameMediaThread=Cambiar el nombre de los archivos multimedia
runKitodoScript=Ejecutar KitodoScript

viewAllAuthorities=Mostrar todos los permisos
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
<p:commandButton id="renameMedia"
widgetVar="renameMedia"
rendered="#{SecurityAccessController.hasAuthorityToRenameMediaFiles()}"
value="#{msgs['dataEditor.renameMedia']}"
value="#{msgs['renameMediaFiles']}"
onclick="deactivateButtons();"
oncomplete="activateButtons();setHeight();"
action="#{DataEditorForm.renameMediaFiles()}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,11 @@
action="#{ProcessForm.generateResultAsPdf}"
ajax="false"
icon="fa fa-file-pdf-o"/>
<p:menuitem id="renameMedia"
rendered="#{SecurityAccessController.hasAuthorityToRenameMediaFiles()}"
value="#{msgs['renameMediaFiles']}"
action="#{ProcessForm.renameMedia}"
icon="fa fa-files-o"/>
</p:menu>
<p:commandButton id="statisticButton" value="#{msgs.statisticalEvaluation}" styleClass="secondary"
icon="fa fa-sort" iconPos="right" process="@this"/>
Expand Down
25 changes: 1 addition & 24 deletions Kitodo/src/test/java/org/kitodo/MockDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.sql.Date;
Expand Down Expand Up @@ -58,7 +57,6 @@
import org.kitodo.api.externaldatamanagement.SearchInterfaceType;
import org.kitodo.api.schemaconverter.FileFormat;
import org.kitodo.api.schemaconverter.MetadataFormat;
import org.kitodo.config.ConfigCore;
import org.kitodo.config.ConfigMain;
import org.kitodo.data.database.beans.Authority;
import org.kitodo.data.database.beans.Batch;
Expand Down Expand Up @@ -125,7 +123,6 @@ public class MockDatabase {
public static final String MEDIA_REFERENCES_TEST_PROCESS_TITLE = "Media";
public static final String METADATA_LOCK_TEST_PROCESS_TITLE = "Metadata lock";
public static final String MEDIA_RENAMING_TEST_PROCESS_TITLE = "Rename media";
public static final String META_XML = "/meta.xml";

public static void startDatabaseServer() throws SQLException {
tcpServer = Server.createTcpServer().start();
Expand Down Expand Up @@ -1117,7 +1114,7 @@ public static int insertTestProcessForRenamingMediaTestIntoSecondProject() throw
* @throws DAOException when loading test project fails
* @throws DataException when saving test process fails
*/
private static int insertTestProcessIntoSecondProject(String processTitle) throws DAOException, DataException {
public static int insertTestProcessIntoSecondProject(String processTitle) throws DAOException, DataException {
Project projectTwo = ServiceManager.getProjectService().getById(2);
Template template = projectTwo.getTemplates().get(0);
Process mediaReferencesProcess = new Process();
Expand Down Expand Up @@ -2101,24 +2098,4 @@ public static Process addProcess(String processTitle, int projectId, int templat
ServiceManager.getProcessService().save(process);
return process;
}

/**
* Copy test metadata xml file with provided 'filename' to process directory of process with provided ID
* 'processId'. Creates directory if it does not exist.
* @param processId process ID
* @param filename filename of metadata file
* @throws IOException when subdirectory cannot be created or metadata file cannot be copied
*/
public static void copyTestMetadataFile(int processId, String filename) throws IOException {
URI processDir = Paths.get(ConfigCore.getKitodoDataDirectory(), String.valueOf(processId))
.toUri();
URI processDirTargetFile = Paths.get(ConfigCore.getKitodoDataDirectory(), processId
+ META_XML).toUri();
URI metaFileUri = Paths.get(ConfigCore.getKitodoDataDirectory(), filename).toUri();
if (!ServiceManager.getFileService().isDirectory(processDir)) {
ServiceManager.getFileService().createDirectory(Paths.get(ConfigCore.getKitodoDataDirectory()).toUri(),
String.valueOf(processId));
}
ServiceManager.getFileService().copyFile(metaFileUri, processDirTargetFile);
}
}
Loading

0 comments on commit 2aac76e

Please sign in to comment.