From c5bc6a861c15385cd02dcb87f5b08095ac205ce3 Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Mon, 25 Mar 2024 16:14:48 +0100 Subject: [PATCH] Run Kitodo Script commands via Active MQ --- .../kitodo/config/enums/ParameterCore.java | 2 + .../interfaces/activemq/ActiveMQDirector.java | 2 +- .../activemq/KitodoScriptProcessor.java | 62 +++++++++++++++++++ .../activemq/MapMessageObjectReader.java | 50 +++++++++++++++ .../main/resources/kitodo_config.properties | 3 + 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessor.java diff --git a/Kitodo/src/main/java/org/kitodo/config/enums/ParameterCore.java b/Kitodo/src/main/java/org/kitodo/config/enums/ParameterCore.java index 70fee5f5879..1f7639ed8ce 100644 --- a/Kitodo/src/main/java/org/kitodo/config/enums/ParameterCore.java +++ b/Kitodo/src/main/java/org/kitodo/config/enums/ParameterCore.java @@ -616,6 +616,8 @@ public enum ParameterCore implements ParameterInterface { ACTIVE_MQ_FINALIZE_STEP_QUEUE(new Parameter("activeMQ.finalizeStep.queue")), + ACTIVE_MQ_KITODO_SCRIPT_QUEUE(new Parameter("activeMQ.kitodoScript.queue")), + ACTIVE_MQ_TASK_ACTION_QUEUE(new Parameter("activeMQ.taskAction.queue")), ACTIVE_MQ_USER(new Parameter("activeMQ.user")), diff --git a/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/ActiveMQDirector.java b/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/ActiveMQDirector.java index 73a2a316b61..0bcd1ee4fdf 100644 --- a/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/ActiveMQDirector.java +++ b/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/ActiveMQDirector.java @@ -57,7 +57,7 @@ public class ActiveMQDirector implements Runnable, ServletContextListener { private static Collection services; static { - services = Arrays.asList(new FinalizeStepProcessor(), new TaskActionProcessor()); + services = Arrays.asList(new FinalizeStepProcessor(), new TaskActionProcessor(), new KitodoScriptProcessor()); } private static Connection connection = null; diff --git a/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessor.java b/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessor.java new file mode 100644 index 00000000000..8c3eadeba42 --- /dev/null +++ b/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessor.java @@ -0,0 +1,62 @@ +/* + * (c) Kitodo. Key to digital objects e. V. + * + * 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.interfaces.activemq; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.jms.JMSException; + +import org.kitodo.config.ConfigCore; +import org.kitodo.config.enums.ParameterCore; +import org.kitodo.data.database.beans.Process; +import org.kitodo.data.database.exceptions.DAOException; +import org.kitodo.data.exceptions.DataException; +import org.kitodo.exceptions.InvalidImagesException; +import org.kitodo.exceptions.MediaNotFoundException; +import org.kitodo.exceptions.ProcessorException; +import org.kitodo.production.services.ServiceManager; +import org.kitodo.production.services.command.KitodoScriptService; +import org.kitodo.production.services.data.ProcessService; + +/** + * Executes instructions to start a Kitodo Script command from the Active MQ + * interface. The MapMessage must contain the command statement in the + * {@code script} argument. You pass a list of the process IDs as + * {@code processes}. + */ +public class KitodoScriptProcessor extends ActiveMQProcessor { + + private final KitodoScriptService kitodoScriptService = ServiceManager.getKitodoScriptService(); + private final ProcessService processService = ServiceManager.getProcessService(); + + public KitodoScriptProcessor() { + super(ConfigCore.getOptionalString(ParameterCore.ACTIVE_MQ_KITODO_SCRIPT_QUEUE).orElse(null)); + } + + @Override + protected void process(MapMessageObjectReader ticket) throws ProcessorException, JMSException { + try { + String script = ticket.getMandatoryString("script"); + Collection processIds = ticket.getCollectionOfInteger("processes"); + List processes = new ArrayList<>(processIds.size()); + for (Integer id : processIds) { + processes.add(processService.getById(id)); + } + kitodoScriptService.execute(processes, script); + } catch (DAOException | DataException | IOException | InvalidImagesException | MediaNotFoundException e) { + throw new ProcessorException(e); + } + } +} diff --git a/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/MapMessageObjectReader.java b/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/MapMessageObjectReader.java index 8149fd11704..76d2ebac51d 100644 --- a/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/MapMessageObjectReader.java +++ b/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/MapMessageObjectReader.java @@ -11,13 +11,16 @@ package org.kitodo.production.interfaces.activemq; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import javax.jms.JMSException; import javax.jms.MapMessage; @@ -110,6 +113,53 @@ public String getMandatoryString(String key) throws JMSException { return mandatoryString; } + /** + * Fetches a {@code Collection} from a MapMessage. This is a loose + * implementation for an optional object with optional content. The + * collection content is filtered through {@code toString()} and split on + * non-digits, dealing generously with list variants and separators. If not + * found, returns an empty collection, never {@code null}. + * + * @param key + * the name of the set to return + * @return the set requested + * @throws JMSException + * can be thrown by MapMessage.getObject(String) + */ + public Collection getCollectionOfInteger(String key) throws JMSException { + Collection collectionOfString = getCollectionOfString(key); + List collectionOfInteger = collectionOfString.stream() + .flatMap(string -> Arrays.stream(string.split("\\D+"))).map(Integer::valueOf) + .collect(Collectors.toList()); + return collectionOfInteger; + } + + /** + * Fetches a {@code Collection} from a MapMessage. This is a loose + * implementation for an optional object with optional content. The + * collection content is filtered through {@code toString()}, {@code null} + * objects will be skipped. If not found, returns an empty collection, never + * {@code null}. + * + * @param key + * the name of the set to return + * @return the set requested + * @throws JMSException + * can be thrown by MapMessage.getObject(String) + */ + public Collection getCollectionOfString(String key) throws JMSException { + + Object collectionObject = ticket.getObject(key); + if (Objects.isNull(collectionObject)) { + return Collections.emptyList(); + } + if (!(collectionObject instanceof Collection)) { + return Collections.singletonList(collectionObject.toString()); + } + return ((Collection) collectionObject).stream().filter(Objects::nonNull).map(Object::toString) + .collect(Collectors.toList()); + } + /** * Fetches a String from a MapMessage. This is an access forward to the * native function of the MapMessage. You may consider to use diff --git a/Kitodo/src/main/resources/kitodo_config.properties b/Kitodo/src/main/resources/kitodo_config.properties index e1fb72ff1c8..1d6fe60e39f 100644 --- a/Kitodo/src/main/resources/kitodo_config.properties +++ b/Kitodo/src/main/resources/kitodo_config.properties @@ -628,6 +628,9 @@ activeMQ.user=testAdmin # You can provide a queue from which messages are read to process task actions #activeMQ.taskAction.queue=KitodoProduction.TaskAction.Queue +# You can provide a queue from which messages are read to run a Kitodo Script +#activeMQ.kitodoScript.queue=KitodoProduction.KitodoScript.Queue + # ----------------------------------- # Elasticsearch properties # -----------------------------------